3939import com .github .javaparser .ast .expr .NormalAnnotationExpr ;
4040import com .github .javaparser .ast .modules .ModuleDeclaration ;
4141import com .github .javaparser .ast .nodeTypes .NodeWithAnnotations ;
42+ import com .github .javaparser .ast .nodeTypes .NodeWithSimpleName ;
4243import com .github .javaparser .ast .nodeTypes .NodeWithType ;
4344import com .github .javaparser .ast .type .ClassOrInterfaceType ;
4445import com .github .javaparser .ast .type .ReferenceType ;
7374
7475import org .apache .commons .lang .StringEscapeUtils ;
7576
76- import static com .azure .tools .apiview .processor .analysers .util .ASTUtils .attemptToFindJavadocComment ;
77- import static com .azure .tools .apiview .processor .analysers .util .ASTUtils .getPackageName ;
78- import static com .azure .tools .apiview .processor .analysers .util .ASTUtils .isInterfaceType ;
79- import static com .azure .tools .apiview .processor .analysers .util .ASTUtils .isPrivateOrPackagePrivate ;
80- import static com .azure .tools .apiview .processor .analysers .util .ASTUtils .isPublicOrProtected ;
81- import static com .azure .tools .apiview .processor .analysers .util .ASTUtils .isTypeAPublicAPI ;
82- import static com .azure .tools .apiview .processor .analysers .util .ASTUtils .makeId ;
77+ import static com .azure .tools .apiview .processor .analysers .util .ASTUtils .*;
8378import static com .azure .tools .apiview .processor .analysers .util .TokenModifier .INDENT ;
8479import static com .azure .tools .apiview .processor .analysers .util .TokenModifier .NEWLINE ;
8580import static com .azure .tools .apiview .processor .analysers .util .TokenModifier .NOTHING ;
@@ -111,19 +106,18 @@ public class JavaASTAnalyser implements Analyser {
111106
112107 private static final Pattern SPLIT_NEWLINE = Pattern .compile (MiscUtils .LINEBREAK );
113108
109+ // This is the model that we build up as the AST of all files are analysed. The APIListing is then output as
110+ // JSON that can be understood by APIView.
114111 private final APIListing apiListing ;
115112
116- private final Map <String , JavadocComment > packageNameToPackageInfoJavaDoc ;
113+ private final Map <String , JavadocComment > packageNameToPackageInfoJavaDoc = new HashMap <>() ;
117114
118- private final Diagnostics diagnostic ;
115+ private final Diagnostics diagnostic = new Diagnostics () ;
119116
120- private int indent ;
117+ private int indent = 0 ;
121118
122- public JavaASTAnalyser (File inputFile , APIListing apiListing ) {
119+ public JavaASTAnalyser (APIListing apiListing ) {
123120 this .apiListing = apiListing ;
124- this .indent = 0 ;
125- this .packageNameToPackageInfoJavaDoc = new HashMap <>();
126- this .diagnostic = new Diagnostics ();
127121 }
128122
129123 @ Override
@@ -183,10 +177,6 @@ public ScanClass(Path path, CompilationUnit compilationUnit) {
183177 }
184178 }
185179
186- public CompilationUnit getCompilationUnit () {
187- return compilationUnit ;
188- }
189-
190180 public Path getPath () {
191181 return path ;
192182 }
@@ -209,7 +199,6 @@ private Optional<ScanClass> scanForTypes(Path path) {
209199 // Set up a minimal type solver that only looks at the classes used to run this sample.
210200 CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver ();
211201 combinedTypeSolver .add (new ReflectionTypeSolver (false ));
212- // combinedTypeSolver.add(new SourceJarTypeSolver(inputFile));
213202
214203 ParserConfiguration parserConfiguration = new ParserConfiguration ()
215204 .setStoreTokens (true )
@@ -343,7 +332,7 @@ private void tokeniseMavenPom(Pom mavenPom) {
343332 // we don't care to present test scope dependencies
344333 return ;
345334 }
346- String scope = k .equals ( "" ) ? "compile" : k ;
335+ String scope = k .isEmpty ( ) ? "compile" : k ;
347336
348337 addToken (makeWhitespace ());
349338 addToken (new Token (COMMENT , "// " + scope + " scope" ), NEWLINE );
@@ -510,6 +499,23 @@ private void visitModuleDeclaration(ModuleDeclaration moduleDeclaration) {
510499 addToken (new Token (TYPE_NAME , moduleDeclaration .getNameAsString (), MODULE_INFO_KEY ), SPACE );
511500 addToken (new Token (PUNCTUATION , "{" ), NEWLINE );
512501
502+ // Sometimes an exports or opens statement is conditional, so we need to handle that case
503+ // in a single location here, to remove duplication.
504+ Consumer <NodeList <Name >> conditionalExportsToOrOpensToConsumer = names -> {
505+ if (!names .isEmpty ()) {
506+ addToken (new Token (WHITESPACE , " " ));
507+ addToken (new Token (KEYWORD , "to" ), SPACE );
508+
509+ for (int i = 0 ; i < names .size (); i ++) {
510+ addToken (new Token (TYPE_NAME , names .get (i ).toString ()));
511+
512+ if (i < names .size () - 1 ) {
513+ addToken (new Token (PUNCTUATION , "," ), SPACE );
514+ }
515+ }
516+ }
517+ };
518+
513519 moduleDeclaration .getDirectives ().forEach (moduleDirective -> {
514520 indent ();
515521 addToken (makeWhitespace ());
@@ -532,43 +538,14 @@ private void visitModuleDeclaration(ModuleDeclaration moduleDeclaration) {
532538 moduleDirective .ifModuleExportsStmt (d -> {
533539 addToken (new Token (KEYWORD , "exports" ), SPACE );
534540 addToken (new Token (TYPE_NAME , d .getNameAsString (), makeId (MODULE_INFO_KEY + "-exports-" + d .getNameAsString ())));
535-
536- NodeList <Name > names = d .getModuleNames ();
537-
538- if (!names .isEmpty ()) {
539- addToken (new Token (WHITESPACE , " " ));
540- addToken (new Token (KEYWORD , "to" ), SPACE );
541-
542- for (int i = 0 ; i < names .size (); i ++) {
543- addToken (new Token (TYPE_NAME , names .get (i ).toString ()));
544-
545- if (i < names .size () - 1 ) {
546- addToken (new Token (PUNCTUATION , "," ), SPACE );
547- }
548- }
549- }
550-
541+ conditionalExportsToOrOpensToConsumer .accept (d .getModuleNames ());
551542 addToken (new Token (PUNCTUATION , ";" ), NEWLINE );
552543 });
553544
554545 moduleDirective .ifModuleOpensStmt (d -> {
555546 addToken (new Token (KEYWORD , "opens" ), SPACE );
556547 addToken (new Token (TYPE_NAME , d .getNameAsString (), makeId (MODULE_INFO_KEY + "-opens-" + d .getNameAsString ())));
557-
558- NodeList <Name > names = d .getModuleNames ();
559- if (names .size () > 0 ) {
560- addToken (new Token (WHITESPACE , " " ));
561- addToken (new Token (KEYWORD , "to" ), SPACE );
562-
563- for (int i = 0 ; i < names .size (); i ++) {
564- addToken (new Token (TYPE_NAME , names .get (i ).toString ()));
565-
566- if (i < names .size () - 1 ) {
567- addToken (new Token (PUNCTUATION , "," ), SPACE );
568- }
569- }
570- }
571-
548+ conditionalExportsToOrOpensToConsumer .accept (d .getModuleNames ());
572549 addToken (new Token (PUNCTUATION , ";" ), NEWLINE );
573550 });
574551
@@ -694,7 +671,13 @@ private void getTypeDeclaration(TypeDeclaration<?> typeDeclaration) {
694671 addToken (new Token (DEPRECATED_RANGE_START ));
695672 }
696673
697- addToken (new Token (TYPE_NAME , className , classId ));
674+ // setting the class name. We need to look up to see if the apiview_properties.json file specified a
675+ // cross language definition id for this type. If it did, we will use that. The apiview_properties.json
676+ // file uses fully-qualified type names and method names, so we need to ensure that it what we are using
677+ // when we look for a match.
678+ Token typeNameToken = new Token (TYPE_NAME , className , classId );
679+ checkForCrossLanguageDefinitionId (typeNameToken , typeDeclaration );
680+ addToken (typeNameToken );
698681
699682 if (isDeprecated ) {
700683 addToken (new Token (DEPRECATED_RANGE_END ));
@@ -755,6 +738,25 @@ private void getTypeDeclaration(TypeDeclaration<?> typeDeclaration) {
755738 addToken (SPACE , new Token (PUNCTUATION , "{" ), NEWLINE );
756739 }
757740
741+ /*
742+ * This method is used to add 'cross language definition id' to the token if it is defined in the
743+ * apiview_properties.json file. This is used most commonly in conjunction with TypeSpec-generated libraries,
744+ * so that we may review cross languages with some level of confidence that the types and methods are the same.
745+ */
746+ private void checkForCrossLanguageDefinitionId (Token typeNameToken , NodeWithSimpleName <?> node ) {
747+ Optional <String > fqn ;
748+ if (node instanceof TypeDeclaration ) {
749+ fqn = ((TypeDeclaration <?>) node ).getFullyQualifiedName ();
750+ } else if (node instanceof CallableDeclaration ) {
751+ fqn = Optional .of (getNodeFullyQualifiedName ((CallableDeclaration <?>) node ));
752+ } else {
753+ fqn = Optional .empty ();
754+ }
755+
756+ fqn .flatMap (_fqn -> apiListing .getApiViewProperties ().getCrossLanguageDefinitionId (_fqn ))
757+ .ifPresent (typeNameToken ::setCrossLanguageDefinitionId );
758+ }
759+
758760 private void tokeniseAnnotationMember (AnnotationDeclaration annotationDeclaration ) {
759761 indent ();
760762 // Member methods in the annotation declaration
@@ -1125,7 +1127,9 @@ private void getDeclarationNameAndParameters(CallableDeclaration<?> callableDecl
11251127 addToken (new Token (DEPRECATED_RANGE_START ));
11261128 }
11271129
1128- addToken (new Token (MEMBER_NAME , name , definitionId ));
1130+ Token nameToken = new Token (MEMBER_NAME , name , definitionId );
1131+ checkForCrossLanguageDefinitionId (nameToken , callableDeclaration );
1132+ addToken (nameToken );
11291133
11301134 if (isDeprecated ) {
11311135 addToken (new Token (DEPRECATED_RANGE_END ));
@@ -1188,7 +1192,7 @@ private void getGenericTypeParameter(TypeParameter typeParameter) {
11881192
11891193 private void getThrowException (CallableDeclaration <?> callableDeclaration ) {
11901194 final NodeList <ReferenceType > thrownExceptions = callableDeclaration .getThrownExceptions ();
1191- if (thrownExceptions .size () == 0 ) {
1195+ if (thrownExceptions .isEmpty () ) {
11921196 return ;
11931197 }
11941198
@@ -1425,7 +1429,7 @@ private void visitJavaDoc(JavadocComment javadoc) {
14251429 // convert http/s links to external clickable links
14261430 Matcher urlMatch = MiscUtils .URL_MATCH .matcher (line2 );
14271431 int currentIndex = 0 ;
1428- while (urlMatch .find (currentIndex ) == true ) {
1432+ while (urlMatch .find (currentIndex )) {
14291433 int start = urlMatch .start ();
14301434 int end = urlMatch .end ();
14311435
0 commit comments