Giter VIP home page Giter VIP logo

methods-distance's Introduction

Builds Dependency Structure Matrix (DSM) for Java class methods. This task is ambitious attempt to improve code read-ability by minimizing user jump/scrolls in source file to look at details of method implementation when user looks at method first usage.

Running:

  • clone sources
  • compile:
mvn package
  • run java -jar methods-distance/target/methods-distance-1.0-SNAPSHOT-jar-with-dependencies.jar --generate-dsm --generate-dot path/to/sources/InputFile.java

This will produce files 'InputFile.java.html' and 'InputFile.java.dot' in working directory.

Alternatively you can try to use web service for generating these files. Web service is hosted at herooku. To get .html file perform GET request at /dsm uri with parameter source_url pointing to url of Java source file. For example: https://methods-distance.herokuapp.com/dsm?source_url=https://raw.githubusercontent.com/checkstyle/checkstyle/b4e884c2ff3bef182b045692b59c1aceae3cb892/src/main/java/com/puppycrawl/tools/checkstyle/Checker.java

To get .dot file perform GET request using /dot uri with parameter source_url. For example https://methods-distance.herokuapp.com/dot?source_url=https://raw.githubusercontent.com/checkstyle/checkstyle/b4e884c2ff3bef182b045692b59c1aceae3cb892/src/main/java/com/puppycrawl/tools/checkstyle/Checker.java

Output .html file will contain design structure matrix of dependencies between methods. This matrix looks like this java file: DSM example

Output .dot file will contain graph of method dependencies in .dot format that can be visualized by many viewers. Viewers:

As an example, here is the output for this java file:

digraph "dependencies" {
rankdir = "LR";
"process(List)" [ color="#00ff00" shape="ellipse" ];
"processFiles(List)" [ color="#000000" shape="ellipse" ];
"Checker()" [ color="#00ff00" shape="ellipse" ];
"setupChild(Configuration)" [ color="#ffff00" shape="trapezium" ];
subgraph clustersimple {
"processFile(File)" [ color="#000000" shape="ellipse" ];
"addFilter(Filter)" [ color="#00ff00" shape="ellipse" ];
"fireFileFinished(String)" [ color="#00ff00" shape="trapezium" ];
"fireFileStarted(String)" [ color="#00ff00" shape="trapezium" ];
"fireAuditStarted()" [ color="#000000" shape="ellipse" ];
"fireErrors(String,SortedSet)" [ color="#00ff00" shape="trapezium" ];
"getExternalResourceLocations()" [ color="#000000" shape="ellipse" ];
"addFileSetCheck(FileSetCheck)" [ color="#00ff00" shape="ellipse" ];
"fireAuditFinished()" [ color="#000000" shape="ellipse" ];
"addListener(AuditListener)" [ color="#00ff00" shape="ellipse" ];
}
"process(List)" -> "getExternalResourceLocations()" [ label="1/35" ];
"process(List)" -> "fireAuditStarted()" [ label="2/55" ];
"process(List)" -> "processFiles(List)" [ label="4/76" ];
"process(List)" -> "fireAuditFinished()" [ label="3/63" ];
"processFiles(List)" -> "fireFileStarted(String)" [ label="2/58" ];
"processFiles(List)" -> "processFile(File)" [ label="1/35" ];
"processFiles(List)" -> "fireErrors(String,SortedSet)" [ label="3/73" ];
"processFiles(List)" -> "fireFileFinished(String)" [ label="4/92" ];
"Checker()" -> "addListener(AuditListener)" [ label="19/327" ];
"setupChild(Configuration)" -> "addFileSetCheck(FileSetCheck)" [ label="1/43" ];
"setupChild(Configuration)" -> "addFilter(Filter)" [ label="2/52" ];
"setupChild(Configuration)" -> "addListener(AuditListener)" [ label="3/60" ];
/*
Legend
Node border color:
    a) GREEN - public
    b) YELLOW - protected
    c) BLACK - private
    d) BLUE - default
Node shape:
    if static - rectangle
    otherwise if override - trapezium
    otherwise if overloaded - triangle
    otherwise ellipse
*/
}

This graph looks like this: Graph example

methods-distance's People

Contributors

alex-zuy avatar dependabot[bot] avatar github-actions[bot] avatar haanhvu avatar josephmate avatar kevin222004 avatar nrmancuso avatar rahulkhinchi03 avatar rnveach avatar romani avatar strkkk avatar vyom-yadav avatar wilcoln avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

methods-distance's Issues

no erros is input file does not exist

Steps:

$ git clone https://github.com/sevntu-checkstyle/methods-distance.git
....
$ cd methods-distance
$ mvn package
..........
$ java -jar methods-distance/target/methods-distance-1.0-SNAPSHOT-jar-with-dependencies.jar --generate-dsm --generate-dot methods-distance/src/main/java/com/github/sevntu/checkstyle/Main111111.java 
$ ll
total 68
drwxrwxr-x 7 rivanov rivanov 4096 Nov 17 11:02 ./
drwxrwxr-x 7 rivanov rivanov 4096 Sep 19 16:47 ../
-rw-rw-r-- 1 rivanov rivanov  983 Nov 17 10:53 appveyor.yml
drwxrwxr-x 2 rivanov rivanov 4096 Sep 19 16:47 config/
-rwxrwxr-x 1 rivanov rivanov 1031 Sep 19 16:47 fast-forward-merge.sh*
drwxrwxr-x 8 rivanov rivanov 4096 Nov 17 11:02 .git/
-rw-rw-r-- 1 rivanov rivanov  304 Sep 19 16:47 .gitignore
drwxrwxr-x 4 rivanov rivanov 4096 Nov 17 10:54 methods-distance/
drwxrwxr-x 4 rivanov rivanov 4096 Nov 17 10:54 methods-distance-web/
-rw-rw-r-- 1 rivanov rivanov 4831 Sep 19 16:47 pom.xml
-rw-rw-r-- 1 rivanov rivanov  131 Sep 19 16:47 Procfile
-rw-rw-r-- 1 rivanov rivanov 4791 Nov 17 11:02 README.md
-rw-rw-r-- 1 rivanov rivanov   79 Sep 19 16:47 system.properties
drwxrwxr-x 2 rivanov rivanov 4096 Nov 17 10:54 target/
-rw-rw-r-- 1 rivanov rivanov  923 Nov 17 10:53 .travis.yml

Expected: exception that file is not found and non-zero exit code .

Changes for README.md about new project name

https://method-graph.herokuapp.com/dsm?source_url=http://site/HelloWorld.java

  1. please change name of application in Heroku
  2. please change this line in README.md
  3. please put in README.md link that is ready to use https://method-graph.herokuapp.com/dsm?source_url=https://github.com/checkstyle/checkstyle/blob/master/src/main/java/com/puppycrawl/tools/checkstyle/Checker.java
  4. README.md should have ready to click examples for all your functionality (graph and dsm).

Upgrade to latest checkstyle library results in test failures

update to 10.10.0

[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ methods-distance ---
[INFO] Surefire report directory: /home/rivanov/java/github/sevntu-checkstyle
  /methods-distance/methods-distance/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.github.sevntu.checkstyle.domain.MethodDefinitionTest
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.412 sec
Running com.github.sevntu.checkstyle.domain.MethodOrderTest
Tests run: 13, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.205 sec
Running com.github.sevntu.checkstyle.domain.ClassDefinitionTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.006 sec
Running com.github.sevntu.checkstyle.domain.MethodOrderReorderTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.027 sec
Running com.github.sevntu.checkstyle.analysis.MethodCallDependencyCheckstyleModuleTest
Tests run: 14, Failures: 0, Errors: 1, Skipped: 1, Time elapsed: 0.182 sec <<< FAILURE!
testMethodSignatures(com.github.sevntu.checkstyle.analysis
  .MethodCallDependencyCheckstyleModuleTest)  Time elapsed: 0.032 sec  <<< ERROR!
java.lang.IllegalStateException: Duplicate key m(int) (attempted merging values m(int) and m(int))
	at java.base/java.util.stream.Collectors.duplicateKeyException(Collectors.java:133)
	at java.base/java.util.stream.Collectors.lambda$uniqKeysMapAccumulator$1(Collectors.java:180)
	at java.base/java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
	at com.github.sevntu.checkstyle.ordering.MethodOrder.getAllMethods(MethodOrder.java:326)
	at com.github.sevntu.checkstyle.ordering.MethodOrder.<init>(MethodOrder.java:61)
	at com.github.sevntu.checkstyle.analysis.MethodCallDependenciesModuleTestSupport.invokeCheckAndGetOrdering(MethodCallDependenciesModuleTestSupport.java:63)
	at com.github.sevntu.checkstyle.analysis.MethodCallDependenciesModuleTestSupport.verifyInfo(MethodCallDependenciesModuleTestSupport.java:51)
	at com.github.sevntu.checkstyle.analysis.MethodCallDependencyCheckstyleModuleTest.testMethodSignatures(MethodCallDependencyCheckstyleModuleTest.java:124)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
	at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
	at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
	at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
	at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
	at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
	at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)


Results :

Tests in error: 
  testMethodSignatures(com.github.sevntu.checkstyle.analysis
    .MethodCallDependencyCheckstyleModuleTest): 
  Duplicate key m(int) (attempted merging values m(int) and m(int))


Code review: phase 2

package com.github.sevntu.checkstyle.analysis;

please rename "analysis" to "domain" as it will be collection of POJO classes that make a domain structure of dependencies that is build by smth from source file and and could be serialized to any(unknown) destination.

public class AnalysisSubject

public class that contains only static content - make it a Util class. No need to keep it as base class for others. The shorter hierarchy the better.


ClassDefinition.java

isInsideMethodOfClass, ... getClassName ,....

All such method should be calculated in c-tor and just give to outside ready to use content.
If it is required occasionally - it should be util method, not a part of this domain class.
Such data can not be changed.

return methods.stream()
                .filter(method -> method.getIndex() == index)
                .findFirst()
                .get();

you mean methods.get(index) ?
please remove all extra java8 usage it does not show you knowledge from good side.

return getMethodsByName(methodName).stream()

do not reuse getMethodsByName, you does not make you code shorter, but create too much extra objects and logic is too abstract.


DependencyInformationConsumer

move this class out of this package


MethodCall

how such public method could return different results on their calls, please pre-calculate all required information and return ready to use answers.
I doubt you need here lazy calculations.


MethodDefinition

this cass is too big, it should by like a structure of ready to use data for Serializers.
Looks like you need to have Builder of this class from AST structure.

PenaltyCalculator.java

move this class out of this package

UnexpectedTokenTypeException.java

move this class out of this package

Build fails on Windows

Project build fails on windows. Steps to reproduce:

  1. Clone sources:
git clone [email protected]:sevntu-checkstyle/methods-distance.git
  1. Enter folder methods-distance-dsm:
cd methods-distance-dsm
  1. Compile project:
mvn package

Build output:

...
testRelativeOrderInconsistency(com.github.sevntu.checkstyle.analysis.OrderingTest)  Time elapsed: 0.007 sec  <<< ERROR!
java.lang.NullPointerException
        at com.github.sevntu.checkstyle.ordering.Ordering.getAllMethods(Ordering.java:264)
        at com.github.sevntu.checkstyle.ordering.Ordering.<init>(Ordering.java:41)
        at com.github.sevntu.checkstyle.analysis.MethodCallDependenciesCheckTestSupport.withDefaultConfigOrdering(MethodCallDependenciesCheckTestSupport.java:91)
        at com.github.sevntu.checkstyle.analysis.OrderingTest.testRelativeOrderInconsistency(OrderingTest.java:95)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
        at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
        at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
        at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
        at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
        at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
        at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)


Results :

Tests in error:
  testSeveralAccessors(com.github.sevntu.checkstyle.analysis.ClassDefinitionTest)
  testMethodCallInInitialization(com.github.sevntu.checkstyle.analysis.MethodCallDependencyCheckTest)
  testNotThisClassMethodCall(com.github.sevntu.checkstyle.analysis.MethodCallDependencyCheckTest)
  testMethodCallsInLambda(com.github.sevntu.checkstyle.analysis.MethodCallDependencyCheckTest)
  testSimpleDependency(com.github.sevntu.checkstyle.analysis.MethodCallDependencyCheckTest)
  testRecursiveMethod(com.github.sevntu.checkstyle.analysis.MethodCallDependencyCheckTest)
  testOverloadedMethods2(com.github.sevntu.checkstyle.analysis.MethodCallDependencyCheckTest)
  testMethodCallThroughMethodReference(com.github.sevntu.checkstyle.analysis.MethodCallDependencyCheckTest)
  testMethodSignatures(com.github.sevntu.checkstyle.analysis.MethodCallDependencyCheckTest)
  testAnonymousClasses(com.github.sevntu.checkstyle.analysis.MethodCallDependencyCheckTest)
  testVarargMethodCall(com.github.sevntu.checkstyle.analysis.MethodCallDependencyCheckTest)
  testAppearanceOrder(com.github.sevntu.checkstyle.analysis.MethodCallDependencyCheckTest)
  testGetterSetterRecognitionsWithCtors(com.github.sevntu.checkstyle.analysis.MethodDefinitionTest)
  testGetterSetterRecognition(com.github.sevntu.checkstyle.analysis.MethodDefinitionTest)
  testReordering(com.github.sevntu.checkstyle.analysis.OrderingReorderTest)
  testOverrideSplit1(com.github.sevntu.checkstyle.analysis.OrderingTest)
  testOverrideSplit2(com.github.sevntu.checkstyle.analysis.OrderingTest)
  testOverrideSplit3(com.github.sevntu.checkstyle.analysis.OrderingTest)
  testCallsBetweenDistantMethods(com.github.sevntu.checkstyle.analysis.OrderingTest)
  testOverloadSplit1(com.github.sevntu.checkstyle.analysis.OrderingTest)
  testOverloadSplit2(com.github.sevntu.checkstyle.analysis.OrderingTest)
  testAccessorsSplit(com.github.sevntu.checkstyle.analysis.OrderingTest)
  testDeclarationBeforeUsageCases(com.github.sevntu.checkstyle.analysis.OrderingTest)
  testTotalSumOfMethodDistances1(com.github.sevntu.checkstyle.analysis.OrderingTest)
  testTotalSumOfMethodDistances2(com.github.sevntu.checkstyle.analysis.OrderingTest)
  testDependencies(com.github.sevntu.checkstyle.analysis.OrderingTest)
  testRelativeOrderInconsistency(com.github.sevntu.checkstyle.analysis.OrderingTest)

Tests run: 28, Failures: 0, Errors: 27, Skipped: 1

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.977 s
[INFO] Finished at: 2016-06-28T15:19:20+03:00
[INFO] Final Memory: 11M/213M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test (default-test) on project methods-distance-dsm: There are test failures.
[ERROR]
[ERROR] Please refer to C:\dev\projects\methods-distance\methods-distance-dsm\target\surefire-reports for the individual test results.
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

Analysis misses some dependencies

This problem was discovered in conversation for PR checkstyle/checkstyle#7960, which is about optimizing the methods distance in checkstyle.api.FileText class.

A quick look at that class shows us that public int size() is used in findLineBreaks(),
but for some reason analysis does not capture that dependency.

To visualize this yourself, checkout the provided dsm report.

activate checkstyle validation

failure like:

[INFO] --- maven-checkstyle-plugin:3.1.2:check (validate) @ methods-distance ---
[INFO] Starting audit...
[ERROR] /home/rivanov/java/github/sevntu-checkstyle/methods-distance
  /methods-distance/src/test/java/com/github/sevntu/
  checkstyle/domain/BaseCheckTestSupport.java:1: 
 Missing a header - not enough lines in file. [header]
[ERROR] /home/rivanov/java/github/sevntu-checkstyle/methods-distance/
  methods-distance/src/test/java/com/github/sevntu/
  checkstyle/domain/ExpectedDependencies.java:1: 
  Missing a header - not enough lines in file. [header]

revert 2aada5e to reproduce

Analysis fails on abstract classes

the command java -jar methods-distance/target/methods-distance-1.0-SNAPSHOT-jar-with-dependencies.jar --generate-dsm --generate-dot /home/wilcoln/checkstyle/src/main/java/com/puppycrawl/tools/checkstyle/api/AbstractFileSetCheck.java

Produces the following error

Starting audit...
Exception in thread "main" com.puppycrawl.tools.checkstyle.api.CheckstyleException: Exception was thrown while processing /home/wilcoln/Workspace/Projects/checkstyle/src/main/java/com/puppycrawl/tools/checkstyle/api/AbstractFileSetCheck.java
	at com.puppycrawl.tools.checkstyle.Checker.processFiles(Checker.java:304)
	at com.puppycrawl.tools.checkstyle.Checker.process(Checker.java:216)
	at com.github.sevntu.checkstyle.common.MethodCallDependencyCheckInvoker.invoke(MethodCallDependencyCheckInvoker.java:77)
	at com.github.sevntu.checkstyle.Main.main(Main.java:62)
Caused by: java.lang.NullPointerException
	at com.github.sevntu.checkstyle.analysis.MethodDefinitionParser.getLength(MethodDefinitionParser.java:265)
	at com.github.sevntu.checkstyle.analysis.MethodDefinitionParser.parse(MethodDefinitionParser.java:78)
	at com.github.sevntu.checkstyle.domain.ClassDefinition.lambda$getDeclaredMethods$0(ClassDefinition.java:62)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
	at com.github.sevntu.checkstyle.domain.ClassDefinition.getDeclaredMethods(ClassDefinition.java:63)
	at com.github.sevntu.checkstyle.domain.ClassDefinition.<init>(ClassDefinition.java:47)
	at com.github.sevntu.checkstyle.module.MethodCallDependencyCheckstyleModule.buildDependencies(MethodCallDependencyCheckstyleModule.java:117)
	at com.github.sevntu.checkstyle.module.MethodCallDependencyCheckstyleModule.lambda$null$0(MethodCallDependencyCheckstyleModule.java:106)
	at java.util.Optional.ifPresent(Optional.java:159)
	at com.github.sevntu.checkstyle.module.MethodCallDependencyCheckstyleModule.lambda$finishTree$1(MethodCallDependencyCheckstyleModule.java:104)
	at java.util.Optional.ifPresent(Optional.java:159)
	at com.github.sevntu.checkstyle.module.MethodCallDependencyCheckstyleModule.finishTree(MethodCallDependencyCheckstyleModule.java:103)
	at com.puppycrawl.tools.checkstyle.TreeWalker.notifyEnd(TreeWalker.java:327)
	at com.puppycrawl.tools.checkstyle.TreeWalker.walk(TreeWalker.java:284)
	at com.puppycrawl.tools.checkstyle.TreeWalker.processFiltered(TreeWalker.java:161)
	at com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck.process(AbstractFileSetCheck.java:85)
	at com.puppycrawl.tools.checkstyle.Checker.processFile(Checker.java:329)
	at com.puppycrawl.tools.checkstyle.Checker.processFiles(Checker.java:291)
	... 3 more

The error message makes me believe that failure is due to an attempt to parse the definition of an abstract method, this is indeed impossible, as such methods do not have any.

Code should be updated to prevent such attempts.

I think that the tool should work on abstract classes as well, since they can sometimes, contain many defined methods for the sake of factorization.

If issue is approved I am willing to work on it.

Code review: part 4

$ tree
.
├── common
│   ├── DependencyInformationConsumerInjector.java
│   └── MethodCallDependencyCheckInvoker.java
├── domain
│   ├── AnalysisUtils.java
│   ├── ClassDefinition.java
│   ├── Dependencies.java
│   ├── MethodCall.java
│   ├── MethodDefinitionBuilder.java
│   ├── MethodDefinition.java
│   ├── RefCall.java
│   └── ResolvedCall.java
├── dot
│   ├── DependencyInfoGraphSerializer.java
│   └── domain
│       ├── AttributeHolder.java
│       ├── Cluster.java
│       ├── Colors.java
│       ├── Comment.java
│       ├── CompositeElement.java
│       ├── Edge.java
│       ├── Element.java
│       ├── Graph.java
│       ├── Node.java
│       ├── Rankdirs.java
│       └── Shapes.java
├── dsm
│   └── DependencyInfoMatrixSerializer.java
├── Main.java
├── module
│   ├── DependencyInformationConsumer.java
│   ├── MethodCallDependencyModule.java
│   └── ViolationReporterDependencyInformationConsumer.java
├── ordering
│   ├── MethodInvocation.java
│   ├── Method.java
│   ├── Ordering.java
│   └── PenaltyCalculator.java
├── reordering
│   ├── MethodReorderer.java
│   └── TopologicalMethodReorderer.java
├── ReorderingCli.java
├── ReportingCli.java
└── utils
    ├── FileUtils.java
    └── UnexpectedTokenTypeException.java

AnalysisUtils, MethodDefinitionBuilder are located in domain package. Domain package is better to be POJO classes. can we move that files outside of this package ?

Rankdirs.java
hmmm, can write javadoc , it is not clear a reason of this class.

  1. ResolvedCall vs RefCall - please specify a difference

ordering and reordering packages.
looks like first is domain and second is actual logic.
does it make sense to be like :

ordering
  +--domain

UnexpectedTokenTypeException it is not utils. It is used not only in Utils, so it belong to "common" to my mind.

Code review: ReportingCli

ReportingCli

please remove SimpleModuleFactory, I do not see its usage. If it is required please make a comment - it is not obvious.

MethodCallDependencyModule

it took me a while to understand why it is a Module. Please rename to "xxxxxxxxxxxCheckstyleModule".
You already have a lot of classes not related to Checkstyle, so we need to make it obvious.

mcdc.addAttribute("screenLinesCount", "50");

please add description of this parameter to javadoc.

final DefaultConfiguration mcdc

please name it final moduleConfig

  • generates violations of method ordering.

you just do reporting of ordering , not a violations. We did not do Check yet, as we do not know rules for now that should be enforced over code.

ReportingCli

rename to ReportCli , "ing" form should be avoided in naming .

Code review: phase 3

project "methods-distance-dsm" do serialization to DOT too , so you cheat by names.

If we want to keep project name we need to move all DOT related classes to separate project
methods-distance-dot and move all common classes to "methods-distance-common" (for all domain classes and checkstyle related classes)
If you do not want to do this - just remove "-dsm" from project name.

Structure still have to be clearly separated by packages:
domain
dot - where DOT serializer is located
dot.domain
dsm

DSM and DOT are different formats with their different demands and dependencies. It might be ok to keep serializers in the same package but their structure classes should not be mixed.

com.github.sevntu.checkstyle.dot

all such classes contain serialization method so they are specific to certain serialization process. Such approach is ok for Prove of Concept period of development but not for long term.
Please move all serialization logic to Serializer.

Code review: phase 1

Main.java

final Configuration config

Please remove "final" from all arguments.
This make s code hard to read.

please add very simple javadoc for Main class to explain a reason of it.


public MethodCallDependencyCheckInvoker(final Configuration methodCallDependencyCheckConfig,
        final DependencyInformationConsumer consumer) throws CheckstyleException {
        final ModuleFactory moduleFactory = new DependencyInformationConsumerInjector(consumer);

put an empty line between method body and signature body should be instantly visible.
Please update all other methods where method signature is not simple.

public MethodCallDependencyCheckInvoker (...

please put empty lines between Checker and Treewalker creation blocks.

class MethodCallDependencyCheckInvoker

if Check name is know already why config is provided . If config is provided - name of class should be general.


ReorderingMain.java

Please put a simple javadoc to explain reason of this CLI interface. "Main" suffix is problem here. please use "Cli" (command line interface).
Some words on what is topological ordering need to be provided.


ReportingMain.java

  1. simple javadoc to explain reason , please add few empty lines in c-tor to clearly show object initialization blocks.

SimpleMuduleFactory

typo, please fix.


MethodCallDependencyCheck.java

  1. it is not a Check (no logging) it is Module that reports some information to another destination.

topLevelClass

as you started to use Optional, this not everywhere ? mixing of null and Optional is bad idea.

ViolationReporterDependencyInformationConsumer

move it to separate class and use it there it is required only. MethodCallDependencyCheck should always demand "consumer" to be provided.
Why only logging for First method ?

consumer.ifPresent(dic -> {

what is "dic" ?

@SuppressWarnings("PMD.UnusedFormalParameter")

each time you use such suppression - you need to put explanation with reason. Please do for all suppressions.

private static ResolvedCall tryResolveCall(

please move CASE blocks to separate methods, very hard to read.

Add constructor below non-constructor penalty

Some users might want constructors to be the first methods defined in class. Thus, it might be relevant to count penalty for every constructor defined below a non-constructor method.

We should come up with a reasonable coefficient for this criterion and modify the global penalty computation logic to take it into consideration.

Code review: Main

Collections.singletonMap("screenLinesCount", "50");

to javadoc

final DependencyInformationSerializer consumer

fix the name of variable

         final MethodCallDependencyCheckInvoker invoker =
            new MethodCallDependencyCheckInvoker(attributes, consumer);
consumer.setConfig(invoker.getConfiguration());

cycle of dependency, not good.

public void accept( MethodCallDependencyModule check,

we do not use that parameter, ..... bad design smell . we need to think twice here.

Please add ability to generate dot and dsm files base on CLI arguments "--generate-dsm", "--generate-dot".
User most likely use only one model that see appropriate for his task.

Service Unavailable

detected at #75 (comment)

service is not awailable as Heroku is not free any more:

there is no free tier any more.

all requests, endup in error, in Heroku logs:
2023-04-15T14:26:48.541486+00:00 heroku[router]: at=error code=H14 desc="No web processes running" method=GET path="/dsm?source_url=https://raw.githubusercontent.com/checkstyle/checkstyle/b4e884c2ff3bef182b045692b59c1aceae3cb892/src/main/java/com/puppycrawl/tools/checkstyle/Checker.java" host=methods-distance.herokuapp.com request_id=a5c18a6e-248a-4578-9033-0d48f1b860a7 fwd="76.103.49.161" dyno= connect= service= status=503 bytes= protocol=https

~/java/github/sevntu-checkstyle/methods-distance [master|✔] 
07:46 $ heroku ps:scale web=1 -a methods-distance
 ›   Warning: heroku update available from 7.69.1 to 8.0.4.
Scaling dynos... !
 ▸    Item Could not be Updated: The app owner has to subscribe to Eco
   to scale your dynos. Learn more at https://blog.heroku.com/new-low-cost-plans

I opened ticket on how to stay free - https://help.heroku.com/tickets/1240314?n=1
They responded, and no more free tiers.


links:
https://help.heroku.com/8GD2AVBW/why-am-i-seeing-an-application-error-after-the-termination-of-free-plans


we need to find new cloud provider for this stateless service.

Convert project to maven aggregator project

Currently project consists of two separate maven sub-projects where methods-distance-web subproject depends on methods-distance by declaring plain maven artifact dependency which is resolved through local repository.
This approach has several drawbacks:

  • It means that whenever we build web subproject we must make shure that we already installed the latest build of methods-distance subproject to maven local repo.
  • To build entire project we need to issue something like following command:
mvn -f methods-distance/pom.xml install && mvn -f methods-distance-web/pom.xml install
  • CI build and deployment scripts gets more complicated

I suggest converting project to maven aggregator project to make build simpler.

Code review: ReorderingCli

  1. rename to ReorderCli

final DependencyInformationSerializer consumer = new DependencyInformationSerializer();

name should be serializer

         final MethodCallDependencyCheckInvoker runner =
            new MethodCallDependencyCheckInvoker(attributes, consumer);
consumer.setConfig(runner.getConfiguration());

runner depends on consumer, consumer depends on runner. Cycle. That is bad design.

            DependencyInfoMatrixSerializer.writeToFile(

source, initialOrdering, configuration, baseName + ".initial.html");

you do not serialize ordering !
ordering is algorithm. You serialize structures that are ordered.

initialOrdering -> initialMethodSequence
topologicalOrdering -> orderedMethodSequence

Ordering

that class need to be renamed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.