@Test public void files() { AstScanner<LexerlessGrammar> scanner = ColdFusionAstScanner.create(new CFConfiguration(Charsets.UTF_8)); scanner.scanFiles( ImmutableList.of( new File("src/test/resources/metrics/Comments.cfc"), new File("src/test/resources/metrics/Functions.cfc"))); SourceProject project = (SourceProject) scanner.getIndex().search(new QueryByType(SourceProject.class)).iterator().next(); assertThat(project.getInt(CFMetric.FILES)).isEqualTo(2); }
/** Helper method for scanning a single file */ public static SourceFile scanSingleFileConfig( File file, CxxConfiguration cxxConfig, SquidAstVisitor<Grammar>... visitors) { if (!file.isFile()) { throw new IllegalArgumentException("File '" + file + "' not found."); } AstScanner<Grammar> scanner = create(cxxConfig, visitors); scanner.scanFile(file); Collection<SourceCode> sources = scanner.getIndex().search(new QueryByType(SourceFile.class)); if (sources.size() != 1) { throw new IllegalStateException( "Only one SourceFile was expected whereas " + sources.size() + " has been returned."); } return (SourceFile) sources.iterator().next(); }
public static AstScanner<Grammar> create( CxxConfiguration conf, SquidAstVisitor<Grammar>... visitors) { final SquidAstVisitorContextImpl<Grammar> context = new SquidAstVisitorContextImpl<>(new SourceProject("Cxx Project")); final Parser<Grammar> parser = CxxParser.create(context, conf); AstScanner.Builder<Grammar> builder = AstScanner.<Grammar>builder(context).setBaseParser(parser); /* Metrics */ builder.withMetrics(CxxMetric.values()); /* Files */ builder.setFilesMetric(CxxMetric.FILES); /* Comments */ builder.setCommentAnalyser( new CommentAnalyser() { @Override public boolean isBlank(String line) { for (int i = 0; i < line.length(); i++) { if (Character.isLetterOrDigit(line.charAt(i))) { return false; } } return true; } @Override public String getContents(String comment) { return "/*".equals(comment.substring(0, 2)) ? comment.substring(2, comment.length() - 2) : comment.substring(2); } }); /* Functions */ builder.withSquidAstVisitor( new SourceCodeBuilderVisitor<>( new SourceCodeBuilderCallback() { @Override public SourceCode createSourceCode(SourceCode parentSourceCode, AstNode astNode) { StringBuilder sb = new StringBuilder(); for (Token token : astNode.getFirstDescendant(CxxGrammarImpl.declaratorId).getTokens()) { sb.append(token.getValue()); } String functionName = sb.toString(); sb.setLength(0); AstNode namespace = astNode.getFirstAncestor(CxxGrammarImpl.originalNamespaceDefinition); while (namespace != null) { if (sb.length() > 0) { sb.insert(0, "::"); } sb.insert( 0, namespace.getFirstDescendant(GenericTokenType.IDENTIFIER).getTokenValue()); namespace = namespace.getFirstAncestor(CxxGrammarImpl.originalNamespaceDefinition); } String namespaceName = sb.length() > 0 ? sb.toString() + "::" : ""; SourceFunction function = new SourceFunction( intersectingConcatenate(namespaceName, functionName) + ":" + astNode.getToken().getLine()); function.setStartAtLine(astNode.getTokenLine()); return function; } }, CxxGrammarImpl.functionDefinition)); builder.withSquidAstVisitor( CounterVisitor.<Grammar>builder() .setMetricDef(CxxMetric.FUNCTIONS) .subscribeTo(CxxGrammarImpl.functionDefinition) .build()); /* Classes */ builder.withSquidAstVisitor( new SourceCodeBuilderVisitor<>( new SourceCodeBuilderCallback() { @Override public SourceCode createSourceCode(SourceCode parentSourceCode, AstNode astNode) { AstNode classNameAst = astNode.getFirstDescendant(CxxGrammarImpl.className); String className = classNameAst == null ? "" : classNameAst.getFirstChild().getTokenValue(); SourceClass cls = new SourceClass(className + ":" + astNode.getToken().getLine(), className); cls.setStartAtLine(astNode.getTokenLine()); return cls; } }, CxxGrammarImpl.classSpecifier)); builder.withSquidAstVisitor( CounterVisitor.<Grammar>builder() .setMetricDef(CxxMetric.CLASSES) .subscribeTo(CxxGrammarImpl.classSpecifier) .build()); /* Metrics */ builder.withSquidAstVisitor(new LinesVisitor<>(CxxMetric.LINES)); builder.withSquidAstVisitor(new CxxLinesOfCodeVisitor<>(CxxMetric.LINES_OF_CODE)); builder.withSquidAstVisitor( new CxxPublicApiVisitor<>(CxxMetric.PUBLIC_API, CxxMetric.PUBLIC_UNDOCUMENTED_API) .withHeaderFileSuffixes(conf.getHeaderFileSuffixes())); builder.withSquidAstVisitor( CommentsVisitor.<Grammar>builder() .withCommentMetric(CxxMetric.COMMENT_LINES) .withNoSonar(true) .withIgnoreHeaderComment(conf.getIgnoreHeaderComments()) .build()); /* Statements */ builder.withSquidAstVisitor( CounterVisitor.<Grammar>builder() .setMetricDef(CxxMetric.STATEMENTS) .subscribeTo(CxxGrammarImpl.statement) .subscribeTo(CxxGrammarImpl.switchBlockStatementGroups) .subscribeTo(CxxGrammarImpl.switchBlockStatementGroup) .build()); AstNodeType[] complexityAstNodeType = new AstNodeType[] { // Entry points CxxGrammarImpl.functionDefinition, CxxKeyword.IF, CxxKeyword.FOR, CxxKeyword.WHILE, CxxKeyword.CATCH, CxxKeyword.CASE, CxxKeyword.DEFAULT, CxxPunctuator.AND, CxxPunctuator.OR, CxxPunctuator.QUEST }; builder.withSquidAstVisitor( ComplexityVisitor.<Grammar>builder() .setMetricDef(CxxMetric.COMPLEXITY) .subscribeTo(complexityAstNodeType) .build()); // to emit a 'new file' event to the internals of the plugin builder.withSquidAstVisitor(new CxxFileVisitor<>(context)); // log syntax errors builder.withSquidAstVisitor(new CxxParseErrorLoggerVisitor<>(context)); /* External visitors (typically Check ones) */ for (SquidAstVisitor<Grammar> visitor : visitors) { if (visitor instanceof CxxCharsetAwareVisitor) { ((CxxCharsetAwareVisitor) visitor).setCharset(conf.getCharset()); } builder.withSquidAstVisitor(visitor); } return builder.build(); }