diff --git a/php-frontend/pom.xml b/php-frontend/pom.xml index 4777e6e0fe..9e2ad7195d 100644 --- a/php-frontend/pom.xml +++ b/php-frontend/pom.xml @@ -14,7 +14,7 @@ - org.codehaus.sonar.sslr + org.sonarsource.sslr sslr-core @@ -26,7 +26,7 @@ sonar-deprecated - org.codehaus.sonar.sslr + org.sonarsource.sslr sslr-testing-harness diff --git a/php-frontend/src/main/java/org/sonar/php/parser/NewPHPGrammar.java b/php-frontend/src/main/java/org/sonar/php/parser/NewPHPGrammar.java new file mode 100644 index 0000000000..d5f25e9810 --- /dev/null +++ b/php-frontend/src/main/java/org/sonar/php/parser/NewPHPGrammar.java @@ -0,0 +1,41 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010 SonarSource and Akram Ben Aissi + * sonarqube@googlegroups.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.php.parser; + +import com.sonar.sslr.api.typed.GrammarBuilder; +import org.sonar.php.tree.impl.lexical.InternalSyntaxToken; +import org.sonar.plugins.php.api.tree.expression.ExpressionTree; + +public class NewPHPGrammar { + + private final GrammarBuilder b; + private final TreeFactory f; + + public NewPHPGrammar(GrammarBuilder b, TreeFactory f) { + this.b = b; + this.f = f; + } + + public ExpressionTree EXPRESSION() { + return b.nonterminal(PHPLexicalGrammar.EXPRESSION) + .is(f.expression(b.token(PHPLexicalGrammar.VARIABLE_IDENTIFIER))); + } + +} diff --git a/php-frontend/src/main/java/org/sonar/php/parser/PHPGrammar.java b/php-frontend/src/main/java/org/sonar/php/parser/PHPGrammar.java index bddf07d9a2..10ba6933d3 100644 --- a/php-frontend/src/main/java/org/sonar/php/parser/PHPGrammar.java +++ b/php-frontend/src/main/java/org/sonar/php/parser/PHPGrammar.java @@ -21,6 +21,11 @@ import com.sonar.sslr.api.GenericTokenType; import org.sonar.php.api.PHPKeyword; +import org.sonar.php.api.PHPPunctuator; +import org.sonar.sslr.grammar.GrammarRuleKey; +import org.sonar.sslr.grammar.LexerlessGrammarBuilder; +import org.sonar.sslr.parser.LexerlessGrammar; + import static org.sonar.php.api.PHPKeyword.ABSTRACT; import static org.sonar.php.api.PHPKeyword.ARRAY; import static org.sonar.php.api.PHPKeyword.AS; @@ -85,7 +90,6 @@ import static org.sonar.php.api.PHPKeyword.VAR; import static org.sonar.php.api.PHPKeyword.WHILE; import static org.sonar.php.api.PHPKeyword.YIELD; -import org.sonar.php.api.PHPPunctuator; import static org.sonar.php.api.PHPPunctuator.AMPERSAND; import static org.sonar.php.api.PHPPunctuator.ANDAND; import static org.sonar.php.api.PHPPunctuator.ANDEQUAL; @@ -141,9 +145,6 @@ import static org.sonar.php.api.PHPPunctuator.TILDA; import static org.sonar.php.api.PHPPunctuator.XOR; import static org.sonar.php.api.PHPPunctuator.XOR_EQU; -import org.sonar.sslr.grammar.GrammarRuleKey; -import org.sonar.sslr.grammar.LexerlessGrammarBuilder; -import org.sonar.sslr.parser.LexerlessGrammar; public enum PHPGrammar implements GrammarRuleKey { diff --git a/php-frontend/src/main/java/org/sonar/php/parser/PHPLexicalGrammar.java b/php-frontend/src/main/java/org/sonar/php/parser/PHPLexicalGrammar.java new file mode 100644 index 0000000000..790c5c04f2 --- /dev/null +++ b/php-frontend/src/main/java/org/sonar/php/parser/PHPLexicalGrammar.java @@ -0,0 +1,330 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010 SonarSource and Akram Ben Aissi + * sonarqube@googlegroups.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.php.parser; + +import com.sonar.sslr.api.GenericTokenType; +import org.sonar.php.api.PHPKeyword; +import org.sonar.php.api.PHPPunctuator; +import org.sonar.sslr.grammar.GrammarRuleKey; +import org.sonar.sslr.grammar.LexerlessGrammarBuilder; +import org.sonar.sslr.parser.LexerlessGrammar; + +public enum PHPLexicalGrammar implements GrammarRuleKey { + + COMPILATION_UNIT, + SCRIPT, + TOP_STATEMENT_LIST, + + /** + * Declaration + */ + USE_DECLARATIONS, + USE_DECLARATION, + USE_FUNCTION_DECLARATION_STATEMENT, + USE_CONST_DECLARATION_STATEMENT, + USE_FUNCTION_DECLARATIONS, + USE_FUNCTION_DECLARATION, + HALT_COMPILER_STATEMENT, + + NAMESPACE_NAME, + UNQUALIFIED_NAME, + QUALIFIED_NAME, + FULLY_QUALIFIED_NAME, + + REFERENCE, + FUNCTION_DECLARATION, + CLASS_DECLARATION, + CLASS_ENTRY_TYPE, + CLASS_TYPE, + FULLY_QUALIFIED_CLASS_NAME, + INTERFACE_LIST, + INTERFACE_DECLARATION, + INTERFACE_EXTENDS_LIST, + EXTENDS_FROM, + IMPLEMENTS_LIST, + CONSTANT_DECLARATION, + CONSTANT_VAR, + + /** + * Lexical + */ + EOF, + HEREDOC, + NUMERIC_LITERAL, + STRING_LITERAL, + STRING_WITH_ENCAPS_VAR_CHARACTERS, + ENCAPS_VAR_IDENTIFIER, + REGULAR_VAR_IDENTIFIER, + VARIABLE_IDENTIFIER, + IDENTIFIER, + FILE_OPENING_TAG, + INLINE_HTML, + KEYWORDS, + + /** + * SPACING + */ + SPACING, + + /** + * End of statement. + */ + EOS, + + /** + * Statement + */ + USE_STATEMENT, + TOP_STATEMENT, + NAMESPACE_STATEMENT, + STATEMENT, + EMPTY_STATEMENT, + LABEL, + BLOCK, + INNER_STATEMENT_LIST, + CLASS_STATEMENT, + IF_STATEMENT, + ELSEIF_LIST, + ELSEIF_CLAUSE, + ELSE_CLAUSE, + ALTERNATIVE_IF_STATEMENT, + ALTERNATIVE_ELSEIF_LIST, + ALTERNATIVE_ELSEIF_CLAUSE, + ALTERNATIVE_ELSE_CLAUSE, + WHILE_STATEMENT, + ALTERNATIVE_WHILE_STATEMENT, + DO_WHILE_STATEMENT, + ALTERNATIVE_DO_WHILE_STATEMENT, + FOR_STATEMENT, + ALTERNATIVE_FOR_STATEMENT, + FOR_EXRR, + FOREACH_STATEMENT, + ALTERNATIVE_FOREACH_STATEMENT, + FOREACH_EXPR, + FOREACH_VARIABLE, + SWITCH_STATEMENT, + SWITCH_CASE_LIST, + CASE_LIST, + CASE_CLAUSE, + DEFAULT_CLAUSE, + CASE_SEPARTOR, + BREAK_STATEMENT, + CONTINUE_STATEMENT, + RETURN_STATEMENT, + DECLARE_STATEMENT, + ALTERNATIVE_DECLARE_STATEMENT, + DECLARE_LIST, + TRY_STATEMENT, + CATCH_STATEMENT, + FINALLY_STATEMENT, + THROW_STATEMENT, + GOTO_STATEMENT, + YIELD_STATEMENT, + GLOBAL_STATEMENT, + GLOBAL_VAR_LIST, + GLOBAL_VAR, + STATIC_STATEMENT, + STATIC_VAR_LIST, + STATIC_VAR, + ECHO_STATEMENT, + UNSET_VARIABLE_STATEMENT, + UNSET_VARIABLES, + PARAMETER_LIST, + PARAMETER, + OPTIONAL_CLASS_TYPE, + METHOD_DECLARATION, + METHOD_BODY, + VARIABLE_MODIFIERS, + CLASS_VARIABLE_DECLARATION, + VARIABLE_DECLARATION, + MEMBER_MODIFIER, + CLASS_CONSTANT_DECLARATION, + MEMBER_CONST_DECLARATION, + TRAIT_USE_STATEMENT, + TRAIT_METHOD_REFERENCE_FULLY_QUALIFIED, + TRAIT_METHOD_REFERENCE, + TRAIT_ALIAS, + TRAIT_PRECEDENCE, + TRAIT_ADAPTATION_STATEMENT, + TRAIT_ADAPTATIONS, + + /** + * Expression + */ + PRIMARY_EXPRESSION, + MEMBER_EXPRESSION, + ALIAS_VARIABLE, + VARIABLE_NAME, + COMPUTED_VARIABLE_NAME, + VARIABLE_WITHOUT_OBJECTS, + EXPRESSION_STATEMENT, + REFERENCE_VARIABLE, + CLASS_MEMBER_ACCESS, + OBJECT_MEMBER_ACCESS, + SIMPLE_INDIRECT_REFERENCE, + STATIC_MEMBER, + COMPOUND_VARIABLE, + CLASS_NAME, + FUNCTION_CALL_PARAMETER_LIST, + PARAMETER_LIST_FOR_CALL, + DIMENSIONAL_OFFSET, + STATIC_SCALAR, + OBJECT_DIM_LIST, + PARENTHESIS_EXPRESSION, + YIELD_EXPRESSION, + COMBINED_SCALAR, + COMMON_SCALAR, + BOOLEAN_LITERAL, + LEXICAL_VARS, + LEXICAL_VAR_LIST, + LEXICAL_VAR, + LOGICAL_XOR_EXPR, + LOGICAL_OR_EXPR, + LOGICAL_OR_OPERATOR, + BITEWISE_AND_EXPR, + BITEWISE_XOR_EXPR, + BITEWISE_OR_EXPR, + LOGICAL_AND_EXPR, + LOGICAL_AND_OPERATOR, + CONDITIONAL_EXPR, + ASSIGNMENT_EXPR, + MULTIPLICATIVE_EXPR, + MULIPLICATIVE_OPERATOR, + ADDITIVE_EXPR, + ADDITIVE_OPERATOR, + SHIFT_EXPR, + SHIFT_OPERATOR, + RELATIONAL_EXPR, + RELATIONAL_OPERATOR, + EQUALITY_EXPR, + EQUALITY_OPERATOR, + CONCATENATION_EXPR, + POSTFIX_EXPR, + UNARY_EXPR, + ASSIGNMENT_BY_REFERENCE, + ASSIGNMENT_OPERATOR, + COMPOUND_ASSIGNMENT, + CAST_TYPE, + LOGICAL_ASSIGNMENT, + INTERNAL_FUNCTION, + NEW_EXPR, + COMBINED_SCALAR_OFFSET, + ARRAY_PAIR_LIST, + ARRAY_PAIR, + EXIT_EXPR, + LIST_EXPR, + LIST_ASSIGNMENT_EXPR, + ASSIGNMENT_LIST_ELEMENT, + ASSIGNMENT_LIST, + FUNCTION_EXPRESSION, + ENCAPS_STRING_LITERAL, + COMPLEX_ENCAPS_VARIABLE, + SEMI_COMPLEX_ENCAPS_VARIABLE, + SEMI_COMPLEX_RECOVERY_EXPRESSION, + SIMPLE_ENCAPS_VARIABLE, + ENCAPS_LIST, + ENCAPS_VAR_OFFSET, + ENCAPS_VAR, + ENCAPS_DIMENSIONAL_OFFSET, + ENCAPS_OBJECT_MEMBER_ACCESS, + + EXPRESSION; + + + public static LexerlessGrammar createGrammar() { + return createGrammarBuilder().build(); + } + + public static LexerlessGrammarBuilder createGrammarBuilder() { + LexerlessGrammarBuilder b = LexerlessGrammarBuilder.create(); + + b.rule(COMPILATION_UNIT).is(b.optional(SCRIPT), SPACING, EOF); + b.rule(SCRIPT).is(FILE_OPENING_TAG, b.optional(TOP_STATEMENT_LIST)); + + // FIXME + b.rule(TOP_STATEMENT_LIST).is(SPACING); + + lexical(b); + punctuators(b); + keywords(b); + + return b; + } + + public static void lexical(LexerlessGrammarBuilder b) { + b.rule(SPACING).is( + b.skippedTrivia(b.regexp("[" + LexicalConstant.LINE_TERMINATOR + LexicalConstant.WHITESPACE + "]*+")), + b.zeroOrMore( + b.commentTrivia(b.regexp(LexicalConstant.COMMENT)), + b.skippedTrivia(b.regexp("[" + LexicalConstant.LINE_TERMINATOR + LexicalConstant.WHITESPACE + "]*+"))) + ).skip(); + + // Literals + b.rule(HEREDOC).is(SPACING, b.regexp(LexicalConstant.HEREDOC)); + b.rule(NUMERIC_LITERAL).is(SPACING, b.regexp(LexicalConstant.NUMERIC_LITERAL)); +// b.rule(STRING_LITERAL).is(SPACING, b.firstOf(b.regexp(LexicalConstant.STRING_LITERAL), ENCAPS_STRING_LITERAL)); + + b.rule(STRING_WITH_ENCAPS_VAR_CHARACTERS).is(b.regexp(LexicalConstant.STRING_WITH_ENCAPS_VAR_CHARACTERS)); +// b.rule(ENCAPS_STRING_LITERAL).is(SPACING, "\"", ENCAPS_LIST, "\""); + + // Identifier + b.rule(ENCAPS_VAR_IDENTIFIER).is( + b.regexp("[" + LexicalConstant.WHITESPACE + "]*+"), + VARIABLE_IDENTIFIER).skip(); + b.rule(REGULAR_VAR_IDENTIFIER).is(SPACING, VARIABLE_IDENTIFIER).skip(); + b.rule(VARIABLE_IDENTIFIER).is(b.regexp(LexicalConstant.VAR_IDENTIFIER)); + b.rule(IDENTIFIER).is(SPACING, b.nextNot(KEYWORDS), b.regexp(LexicalConstant.IDENTIFIER)); + + // Tags & Inline HTML + b.rule(FILE_OPENING_TAG).is(SPACING, b.token(PHPTokenType.FILE_OPENING_TAG, b.regexp(LexicalConstant.PHP_START_TAG))).skip(); + b.rule(INLINE_HTML).is(SPACING, b.token(PHPTokenType.INLINE_HTML, b.regexp(LexicalConstant.PHP_END_TAG))).skip(); + + b.rule(EOF).is(b.token(GenericTokenType.EOF, b.endOfInput())).skip(); + } + + private static void keywords(LexerlessGrammarBuilder b) { + Object[] rest = new Object[PHPKeyword.values().length - 2]; + + for (int i = 0; i < PHPKeyword.values().length; i++) { + PHPKeyword tokenType = PHPKeyword.values()[i]; + + // PHP keywords are case insensitive + b.rule(tokenType).is(SPACING, b.token(tokenType, b.regexp("(?i)" + tokenType.getValue())), b.nextNot(b.regexp(LexicalConstant.IDENTIFIER_PART))).skip(); + if (i > 1) { + rest[i - 2] = b.regexp("(?i)" + tokenType.getValue()); + } + } + + b.rule(KEYWORDS).is(SPACING, + b.firstOf( + PHPKeyword.getKeywordValues()[0], + PHPKeyword.getKeywordValues()[1], + rest), + b.nextNot(b.regexp(LexicalConstant.IDENTIFIER_PART)) + ); + } + + private static void punctuators(LexerlessGrammarBuilder b) { + for (PHPPunctuator p : PHPPunctuator.values()) { + b.rule(p).is(SPACING, b.token(p, p.getValue())).skip(); + } + } + +} diff --git a/php-frontend/src/main/java/org/sonar/php/parser/PHPNodeBuilder.java b/php-frontend/src/main/java/org/sonar/php/parser/PHPNodeBuilder.java new file mode 100644 index 0000000000..b14cbf85b0 --- /dev/null +++ b/php-frontend/src/main/java/org/sonar/php/parser/PHPNodeBuilder.java @@ -0,0 +1,118 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010 SonarSource and Akram Ben Aissi + * sonarqube@googlegroups.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.php.parser; + +import com.google.common.collect.Lists; +import com.sonar.sslr.api.GenericTokenType; +import com.sonar.sslr.api.Rule; +import com.sonar.sslr.api.Token; +import com.sonar.sslr.api.TokenType; +import com.sonar.sslr.api.Trivia; +import com.sonar.sslr.api.typed.Input; +import com.sonar.sslr.api.typed.NodeBuilder; +import org.sonar.php.tree.impl.PHPTree; +import org.sonar.php.tree.impl.lexical.InternalSyntaxToken; +import org.sonar.php.tree.impl.lexical.InternalSyntaxTrivia; +import org.sonar.plugins.php.api.tree.Tree; +import org.sonar.plugins.php.api.tree.lexical.SyntaxTrivia; +import org.sonar.plugins.php.api.visitors.TreeVisitor; +import org.sonar.sslr.grammar.GrammarRuleKey; + +import java.util.Iterator; +import java.util.List; + +public class PHPNodeBuilder implements NodeBuilder { + + @Override + public Object createNonTerminal(GrammarRuleKey ruleKey, Rule rule, List children, int startIndex, int endIndex) { + for (Object child : children) { + if (child instanceof InternalSyntaxToken) { + return child; + } + } + return new InternalSyntaxSpacing(); + } + + @Override + public Object createTerminal(Input input, int startIndex, int endIndex, List trivias, TokenType type) { + boolean isEof = GenericTokenType.EOF.equals(type); + LineColumnValue lineColumnValue = tokenPosition(input, startIndex, endIndex); + return new InternalSyntaxToken( + lineColumnValue.line, + lineColumnValue.column, + lineColumnValue.value, + createTrivias(trivias), + startIndex, + isEof + ); + } + + private static List createTrivias(List trivias) { + List result = Lists.newArrayList(); + for (Trivia trivia : trivias) { + Token trivialToken = trivia.getToken(); + result.add(InternalSyntaxTrivia.create(trivialToken.getValue(), trivialToken.getLine(), trivialToken.getColumn())); + } + return result; + } + + private static LineColumnValue tokenPosition(Input input, int startIndex, int endIndex) { + int[] lineAndColumn = input.lineAndColumnAt(startIndex); + String value = input.substring(startIndex, endIndex); + return new LineColumnValue(lineAndColumn[0], lineAndColumn[1] - 1, value); + } + + private static class LineColumnValue { + final int line; + final int column; + final String value; + + private LineColumnValue(int line, int column, String value) { + this.line = line; + this.column = column; + this.value = value; + } + } + + private static class InternalSyntaxSpacing extends PHPTree { + + @Override + public void accept(TreeVisitor visitor) { + // nothing to do + } + + @Override + public Kind getKind() { + return Kind.TRIVIA; + } + + @Override + public Iterator childrenIterator() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isLeaf() { + return true; + } + + } + +} diff --git a/php-frontend/src/main/java/org/sonar/php/parser/PHPParserBuilder.java b/php-frontend/src/main/java/org/sonar/php/parser/PHPParserBuilder.java new file mode 100644 index 0000000000..8c6f824dad --- /dev/null +++ b/php-frontend/src/main/java/org/sonar/php/parser/PHPParserBuilder.java @@ -0,0 +1,60 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010 SonarSource and Akram Ben Aissi + * sonarqube@googlegroups.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.php.parser; + +import com.sonar.sslr.api.typed.ActionParser; +import org.sonar.plugins.php.api.tree.Tree; + +import java.nio.charset.Charset; + +public class PHPParserBuilder { + + private PHPParserBuilder(){ + } + + public static ActionParser createParser(Charset charset) { + return new ActionParser<>( + charset, + PHPLexicalGrammar.createGrammarBuilder(), + NewPHPGrammar.class, + new TreeFactory(), + new PHPNodeBuilder(), + PHPLexicalGrammar.COMPILATION_UNIT); + } + + /** + * This method should be used by tests only. + * Provides ability to start parsing from some rule other than PHPLexicalGrammar.COMPILATION_UNIT. + * @param rootRule rule from which parsing starts + * @param charset + */ + public static ActionParser createParser(PHPLexicalGrammar rootRule, Charset charset) { + return new ActionParser<>( + charset, + PHPLexicalGrammar.createGrammarBuilder(), + NewPHPGrammar.class, + new TreeFactory(), + new PHPNodeBuilder(), + rootRule); + } + + + +} diff --git a/php-frontend/src/main/java/org/sonar/php/parser/TreeFactory.java b/php-frontend/src/main/java/org/sonar/php/parser/TreeFactory.java new file mode 100644 index 0000000000..441fda89d1 --- /dev/null +++ b/php-frontend/src/main/java/org/sonar/php/parser/TreeFactory.java @@ -0,0 +1,32 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010 SonarSource and Akram Ben Aissi + * sonarqube@googlegroups.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.php.parser; + +import org.sonar.php.tree.impl.VariableIdentifierTreeImpl; +import org.sonar.php.tree.impl.expression.IdentifierTreeImpl; +import org.sonar.php.tree.impl.lexical.InternalSyntaxToken; +import org.sonar.plugins.php.api.tree.expression.ExpressionTree; + +public class TreeFactory { + + public ExpressionTree expression(InternalSyntaxToken token) { + return new VariableIdentifierTreeImpl(new IdentifierTreeImpl(token)); + } +} diff --git a/php-frontend/src/main/java/org/sonar/php/tree/impl/PHPTree.java b/php-frontend/src/main/java/org/sonar/php/tree/impl/PHPTree.java new file mode 100644 index 0000000000..1a83c767be --- /dev/null +++ b/php-frontend/src/main/java/org/sonar/php/tree/impl/PHPTree.java @@ -0,0 +1,87 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010 SonarSource and Akram Ben Aissi + * sonarqube@googlegroups.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.php.tree.impl; + +import org.sonar.plugins.php.api.tree.Tree; +import org.sonar.plugins.php.api.tree.lexical.SyntaxToken; + +import java.util.Iterator; + +public abstract class PHPTree implements Tree { + + public int getLine() { + return getFirstToken().line(); + } + + @Override + public final boolean is(Kind... kind) { + if (getKind() != null) { + for (Kind kindIter : kind) { + if (getKind() == kindIter) { + return true; + } + } + } + return false; + } + + public abstract Kind getKind(); + + /** + * Creates iterator for children of this node. + * Note that iterator may contain {@code null} elements. + * + * @throws UnsupportedOperationException if {@link #isLeaf()} returns {@code true} + */ + public abstract Iterator childrenIterator(); + + public boolean isLeaf() { + return false; + } + + public SyntaxToken getLastToken() { + SyntaxToken lastToken = null; + Iterator childrenIterator = childrenIterator(); + while (childrenIterator.hasNext()) { + PHPTree child = (PHPTree) childrenIterator.next(); + if (child != null) { + SyntaxToken childLastToken = child.getLastToken(); + if (childLastToken != null) { + lastToken = childLastToken; + } + } + } + return lastToken; + } + + public SyntaxToken getFirstToken() { + Iterator childrenIterator = childrenIterator(); + Tree child; + do { + if (childrenIterator.hasNext()) { + child = childrenIterator.next(); + } else { + throw new IllegalStateException("Tree has no non-null children " + getKind()); + } + } while (child == null); + return ((PHPTree) child).getFirstToken(); + } +} + diff --git a/php-frontend/src/main/java/org/sonar/php/tree/impl/VariableIdentifierTreeImpl.java b/php-frontend/src/main/java/org/sonar/php/tree/impl/VariableIdentifierTreeImpl.java new file mode 100644 index 0000000000..8a048e6acc --- /dev/null +++ b/php-frontend/src/main/java/org/sonar/php/tree/impl/VariableIdentifierTreeImpl.java @@ -0,0 +1,62 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010 SonarSource and Akram Ben Aissi + * sonarqube@googlegroups.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.php.tree.impl; + +import com.google.common.collect.Iterators; +import org.sonar.php.tree.impl.expression.IdentifierTreeImpl; +import org.sonar.php.tree.impl.lexical.InternalSyntaxToken; +import org.sonar.plugins.php.api.tree.Tree; +import org.sonar.plugins.php.api.tree.expression.IdentifierTree; +import org.sonar.plugins.php.api.tree.expression.VariableIdentifierTree; +import org.sonar.plugins.php.api.tree.lexical.SyntaxToken; +import org.sonar.plugins.php.api.visitors.TreeVisitor; + +import java.util.Iterator; + +public class VariableIdentifierTreeImpl extends PHPTree implements VariableIdentifierTree { + + private final IdentifierTree token; + private static final Kind KIND = Kind.VARIABLE_IDENTIFIER; + + + public VariableIdentifierTreeImpl(IdentifierTreeImpl token) { + this.token = token; + } + + @Override + public Kind getKind() { + return KIND; + } + + @Override + public Iterator childrenIterator() { + return Iterators.singletonIterator(token); + } + + @Override + public void accept(TreeVisitor visitor) { + visitor.visitVariableIdentifier(this); + } + + @Override + public IdentifierTree variableExpression() { + return token; + } +} diff --git a/php-frontend/src/main/java/org/sonar/php/tree/impl/expression/IdentifierTreeImpl.java b/php-frontend/src/main/java/org/sonar/php/tree/impl/expression/IdentifierTreeImpl.java new file mode 100644 index 0000000000..b655b30619 --- /dev/null +++ b/php-frontend/src/main/java/org/sonar/php/tree/impl/expression/IdentifierTreeImpl.java @@ -0,0 +1,72 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010 SonarSource and Akram Ben Aissi + * sonarqube@googlegroups.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.php.tree.impl.expression; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Iterators; +import org.sonar.php.tree.impl.PHPTree; +import org.sonar.php.tree.impl.lexical.InternalSyntaxToken; +import org.sonar.plugins.php.api.tree.Tree; +import org.sonar.plugins.php.api.tree.expression.IdentifierTree; +import org.sonar.plugins.php.api.tree.lexical.SyntaxToken; +import org.sonar.plugins.php.api.visitors.TreeVisitor; + +import java.util.Iterator; + +public class IdentifierTreeImpl extends PHPTree implements IdentifierTree { + + private final InternalSyntaxToken nameToken; + private static final Kind KIND = Kind.IDENTIFIER; + + public IdentifierTreeImpl(InternalSyntaxToken nameToken) { + this.nameToken = Preconditions.checkNotNull(nameToken); + } + + @Override + public Kind getKind() { + return KIND; + } + + + @Override + public SyntaxToken token() { + return nameToken; + } + + @Override + public String name() { + return token().text(); + } + + @Override + public String toString() { + return name(); + } + + @Override + public Iterator childrenIterator() { + return Iterators.singletonIterator(nameToken); + } + + @Override + public void accept(TreeVisitor visitor) { + visitor.visitIdentifier(this); + } +} diff --git a/php-frontend/src/main/java/org/sonar/php/tree/impl/lexical/InternalSyntaxToken.java b/php-frontend/src/main/java/org/sonar/php/tree/impl/lexical/InternalSyntaxToken.java index aab9231de8..29c8d2f90d 100644 --- a/php-frontend/src/main/java/org/sonar/php/tree/impl/lexical/InternalSyntaxToken.java +++ b/php-frontend/src/main/java/org/sonar/php/tree/impl/lexical/InternalSyntaxToken.java @@ -20,12 +20,16 @@ package org.sonar.php.tree.impl.lexical; import com.sonar.sslr.api.TokenType; +import org.sonar.php.tree.impl.PHPTree; +import org.sonar.plugins.php.api.tree.Tree; import org.sonar.plugins.php.api.tree.lexical.SyntaxToken; import org.sonar.plugins.php.api.tree.lexical.SyntaxTrivia; +import org.sonar.plugins.php.api.visitors.TreeVisitor; +import java.util.Iterator; import java.util.List; -public class InternalSyntaxToken implements SyntaxToken { +public class InternalSyntaxToken extends PHPTree implements SyntaxToken { private List trivias; private int startIndex; @@ -80,8 +84,23 @@ public boolean is(TokenType type) { } @Override - public boolean is(Kind... kind) { - throw new UnsupportedOperationException("Not implemented yet"); + public Kind getKind() { + return Kind.TOKEN; + } + + @Override + public Iterator childrenIterator() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isLeaf() { + return true; + } + + @Override + public void accept(TreeVisitor visitor) { + // FIXME do nothing at the moment } } diff --git a/php-frontend/src/main/java/org/sonar/php/tree/impl/lexical/InternalSyntaxTrivia.java b/php-frontend/src/main/java/org/sonar/php/tree/impl/lexical/InternalSyntaxTrivia.java new file mode 100644 index 0000000000..70289ea932 --- /dev/null +++ b/php-frontend/src/main/java/org/sonar/php/tree/impl/lexical/InternalSyntaxTrivia.java @@ -0,0 +1,93 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010 SonarSource and Akram Ben Aissi + * sonarqube@googlegroups.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.php.tree.impl.lexical; + + +import org.sonar.php.tree.impl.PHPTree; +import org.sonar.plugins.php.api.tree.Tree; +import org.sonar.plugins.php.api.tree.lexical.SyntaxTrivia; +import org.sonar.plugins.php.api.visitors.TreeVisitor; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +public class InternalSyntaxTrivia extends PHPTree implements SyntaxTrivia { + + private final String comment; + private final int column; + private int startLine; + + public InternalSyntaxTrivia(String comment, int startLine, int column) { + this.comment = comment; + this.startLine = startLine; + this.column = column; + } + + @Override + public String text() { + return comment; + } + + @Override + public List trivias() { + return Collections.emptyList(); + } + + @Override + public int line() { + return startLine; + } + + @Override + public int column() { + return column; + } + + @Override + public Kind getKind() { + return Kind.TRIVIA; + } + + @Override + public boolean isLeaf() { + return true; + } + + @Override + public Iterator childrenIterator() { + throw new UnsupportedOperationException(); + } + + public static SyntaxTrivia create(String comment, int startLine, int column) { + return new InternalSyntaxTrivia(comment, startLine, column); + } + + @Override + public int getLine() { + return startLine; + } + + @Override + public void accept(TreeVisitor visitor) { + //FIXME do nothing + } +} + diff --git a/php-frontend/src/main/java/org/sonar/php/tree/visitors/SubscriptionAstTreeVisitor.java b/php-frontend/src/main/java/org/sonar/php/tree/visitors/SubscriptionAstTreeVisitor.java new file mode 100644 index 0000000000..f1f43e6a72 --- /dev/null +++ b/php-frontend/src/main/java/org/sonar/php/tree/visitors/SubscriptionAstTreeVisitor.java @@ -0,0 +1,107 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010 SonarSource and Akram Ben Aissi + * sonarqube@googlegroups.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.php.tree.visitors; + +import org.sonar.php.tree.impl.PHPTree; +import org.sonar.plugins.php.api.tree.Tree; +import org.sonar.plugins.php.api.tree.lexical.SyntaxToken; +import org.sonar.plugins.php.api.tree.lexical.SyntaxTrivia; +import org.sonar.plugins.php.api.visitors.PHPCheck; +import org.sonar.plugins.php.api.visitors.TreeVisitorContext; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +public abstract class SubscriptionAstTreeVisitor implements PHPCheck { + + private TreeVisitorContext context; + private Collection nodesToVisit; + + public abstract List nodesToVisit(); + + @Override + public TreeVisitorContext getContext() { + return context; + } + + public void visitNode(Tree tree) { + // Default behavior : do nothing. + } + + public void leaveNode(Tree tree) { + // Default behavior : do nothing. + } + + public void visitToken(SyntaxToken syntaxToken) { + // default behaviour is to do nothing + } + + public void visitTrivia(SyntaxTrivia syntaxTrivia) { + // default behaviour is to do nothing + } + + public void visitFile(Tree scriptTree) { + // default behaviour is to do nothing + } + + @Override + public void scanFile(TreeVisitorContext context) { + this.context = context; + visitFile(context.getTopTree()); + scanTree(context.getTopTree()); + } + + protected void scanTree(Tree tree) { + nodesToVisit = nodesToVisit(); + visit(tree); + } + + private void visit(Tree tree) { + boolean isSubscribed = isSubscribed(tree); + if (isSubscribed) { + visitNode(tree); + } + visitChildren(tree); + if (isSubscribed) { + leaveNode(tree); + } + } + + protected boolean isSubscribed(Tree tree) { + return nodesToVisit.contains(((PHPTree) tree).getKind()); + } + + private void visitChildren(Tree tree) { + PHPTree javaTree = (PHPTree) tree; + + if (!javaTree.isLeaf()) { + for (Iterator iter = javaTree.childrenIterator(); iter.hasNext();) { + Tree next = iter.next(); + + if (next != null) { + visit(next); + } + } + } + } + +} + diff --git a/php-frontend/src/main/java/org/sonar/plugins/php/api/tree/Tree.java b/php-frontend/src/main/java/org/sonar/plugins/php/api/tree/Tree.java index facb25c33d..33b046ed19 100644 --- a/php-frontend/src/main/java/org/sonar/plugins/php/api/tree/Tree.java +++ b/php-frontend/src/main/java/org/sonar/plugins/php/api/tree/Tree.java @@ -19,8 +19,10 @@ */ package org.sonar.plugins.php.api.tree; +import com.google.common.annotations.Beta; +import com.sonar.sslr.api.AstNodeType; +import org.sonar.plugins.php.api.tree.declaration.ClassDeclarationTree; import org.sonar.plugins.php.api.tree.declaration.ClassFieldDeclarationTree; -import org.sonar.plugins.php.api.tree.declaration.ClassTree; import org.sonar.plugins.php.api.tree.declaration.FunctionDeclarationTree; import org.sonar.plugins.php.api.tree.declaration.MethodDeclarationTree; import org.sonar.plugins.php.api.tree.declaration.NamespacedNameTree; @@ -41,6 +43,7 @@ import org.sonar.plugins.php.api.tree.expression.ExpandableStringLiteralTree; import org.sonar.plugins.php.api.tree.expression.FunctionCallTree; import org.sonar.plugins.php.api.tree.expression.FunctionExpressionTree; +import org.sonar.plugins.php.api.tree.expression.IdentifierTree; import org.sonar.plugins.php.api.tree.expression.LexicalVariablesTree; import org.sonar.plugins.php.api.tree.expression.ListExpressionTree; import org.sonar.plugins.php.api.tree.expression.LiteralTree; @@ -53,6 +56,7 @@ import org.sonar.plugins.php.api.tree.expression.VariableIdentifierTree; import org.sonar.plugins.php.api.tree.expression.VariableVariableTree; import org.sonar.plugins.php.api.tree.lexical.SyntaxToken; +import org.sonar.plugins.php.api.tree.lexical.SyntaxTrivia; import org.sonar.plugins.php.api.tree.statement.BlockTree; import org.sonar.plugins.php.api.tree.statement.BreakStatementTree; import org.sonar.plugins.php.api.tree.statement.CaseClauseTree; @@ -82,11 +86,9 @@ import org.sonar.plugins.php.api.tree.statement.TryStatementTree; import org.sonar.plugins.php.api.tree.statement.WhileStatementTree; import org.sonar.plugins.php.api.tree.statement.YieldStatementTree; +import org.sonar.plugins.php.api.visitors.TreeVisitor; import org.sonar.sslr.grammar.GrammarRuleKey; -import com.google.common.annotations.Beta; -import com.sonar.sslr.api.AstNodeType; - /** * Common interface for all nodes in an abstract syntax tree. */ @@ -95,22 +97,24 @@ public interface Tree { boolean is(Kind... kind); + void accept(TreeVisitor visitor); + public enum Kind implements AstNodeType, GrammarRuleKey { /** - * {@link ClassTree} + * {@link ClassDeclarationTree} */ - CLASS_DECLARATION(ClassTree.class), + CLASS_DECLARATION(ClassDeclarationTree.class), /** - * {@link ClassTree} + * {@link ClassDeclarationTree} */ - INTERFACE_DECLARATION(ClassTree.class), + INTERFACE_DECLARATION(ClassDeclarationTree.class), /** - * {@link ClassTree} + * {@link ClassDeclarationTree} */ - TRAIT_DECLARATION(ClassTree.class), + TRAIT_DECLARATION(ClassDeclarationTree.class), /** * {@link MethodDeclarationTree} @@ -182,6 +186,11 @@ public enum Kind implements AstNodeType, GrammarRuleKey { */ VARIABLE_IDENTIFIER(VariableIdentifierTree.class), + /** + * {@link IdentifierTree} + */ + IDENTIFIER(IdentifierTree.class), + /** * {@link ReferenceVariableTree} */ @@ -772,6 +781,11 @@ public enum Kind implements AstNodeType, GrammarRuleKey { */ TRAIT_ALIAS(TraitAliasTree.class), + /** + * {@link SyntaxToken} + */ + TRIVIA(SyntaxTrivia.class), + /** * {@link SyntaxToken} */ diff --git a/php-frontend/src/main/java/org/sonar/plugins/php/api/visitors/PHPCheck.java b/php-frontend/src/main/java/org/sonar/plugins/php/api/visitors/PHPCheck.java new file mode 100644 index 0000000000..e6d0966751 --- /dev/null +++ b/php-frontend/src/main/java/org/sonar/plugins/php/api/visitors/PHPCheck.java @@ -0,0 +1,34 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010 SonarSource and Akram Ben Aissi + * sonarqube@googlegroups.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.php.api.visitors; + +import com.google.common.annotations.Beta; +import org.sonar.squidbridge.api.CodeVisitor; + +/** + * Marker interface for all JavaScript checks. + */ +@Beta +public interface PHPCheck { + + TreeVisitorContext getContext(); + + void scanFile(TreeVisitorContext context); +} diff --git a/php-frontend/src/main/java/org/sonar/plugins/php/api/visitors/TreeVisitor.java b/php-frontend/src/main/java/org/sonar/plugins/php/api/visitors/TreeVisitor.java new file mode 100644 index 0000000000..d71746eba8 --- /dev/null +++ b/php-frontend/src/main/java/org/sonar/plugins/php/api/visitors/TreeVisitor.java @@ -0,0 +1,34 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010 SonarSource and Akram Ben Aissi + * sonarqube@googlegroups.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.php.api.visitors; + +import com.google.common.annotations.Beta; +import org.sonar.php.tree.impl.expression.IdentifierTreeImpl; +import org.sonar.plugins.php.api.tree.expression.IdentifierTree; +import org.sonar.plugins.php.api.tree.expression.VariableIdentifierTree; + +@Beta +public interface TreeVisitor { + + void visitVariableIdentifier(VariableIdentifierTree tree); + + void visitIdentifier(IdentifierTreeImpl identifierTree); +} + diff --git a/php-frontend/src/main/java/org/sonar/plugins/php/api/visitors/TreeVisitorContext.java b/php-frontend/src/main/java/org/sonar/plugins/php/api/visitors/TreeVisitorContext.java new file mode 100644 index 0000000000..455eddf1aa --- /dev/null +++ b/php-frontend/src/main/java/org/sonar/plugins/php/api/visitors/TreeVisitorContext.java @@ -0,0 +1,96 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010 SonarSource and Akram Ben Aissi + * sonarqube@googlegroups.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.php.api.visitors; + +import com.google.common.annotations.Beta; +import org.sonar.plugins.php.api.tree.Tree; + +import java.io.File; + +@Beta +public interface TreeVisitorContext { + + /** + * @return the top tree node of the current file AST representation. + */ + //fixme ScriptTree + Tree getTopTree(); + + /** + * Creates an issue. + * + * @param check instance of the check that creates the issue. + * @param tree the tree on which the issue should be raise. Means the issue will be raised on its corresponding line in the source code. + * @param message the issue message. + */ + void addIssue(PHPCheck check, Tree tree, String message); + + /** + * Creates an issue. + * + * @param check instance of the check that create the issue + * @param line source line on which the issue should be raised + * @param message the issue message + */ + void addIssue(PHPCheck check, int line, String message); + + /** + * Creates an issue. + * + * @param check instance of the check that create the issue + * @param tree the tree on which the issue should be raise. Means the issue will be raised on its corresponding line in the source code. + * @param message the issue message + * @param cost specific remediation cost for the issue, used to compute the technical debt + */ + void addIssue(PHPCheck check, Tree tree, String message, double cost); + + /** + * Creates an issue. + * + * @param check instance of the check that create the issue + * @param line source line on which the issue should be raised + * @param message the issue message + * @param cost specific remediation cost for the issue, used to compute the technical debt + */ + void addIssue(PHPCheck check, int line, String message, double cost); + + /** + * Creates an issue at a file level. + * + * @param check instance of the check that create the issue + * @param message the issue message + */ + void addFileIssue(PHPCheck check, String message); + + /** + * @return the current file + */ + File getFile(); + + /** + * Fetch project property + * + * @param name property key + * + * @return the value for the given key + */ + String[] getPropertyValues(String name); + +} \ No newline at end of file diff --git a/php-frontend/src/test/java/org/sonar/php/PHPTreeModelTest.java b/php-frontend/src/test/java/org/sonar/php/PHPTreeModelTest.java new file mode 100644 index 0000000000..38167649a4 --- /dev/null +++ b/php-frontend/src/test/java/org/sonar/php/PHPTreeModelTest.java @@ -0,0 +1,77 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010 SonarSource and Akram Ben Aissi + * sonarqube@googlegroups.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.php; + +import com.google.common.base.Charsets; +import com.sonar.sslr.api.RecognitionException; +import com.sonar.sslr.api.typed.ActionParser; +import com.sonar.sslr.impl.ast.AstXmlPrinter; +import org.sonar.php.parser.PHPLexicalGrammar; +import org.sonar.php.parser.PHPParserBuilder; +import org.sonar.php.tree.impl.PHPTree; +import org.sonar.php.tree.impl.lexical.InternalSyntaxToken; +import org.sonar.php.utils.SourceBuilder; +import org.sonar.plugins.php.api.tree.Tree; +import org.sonar.plugins.php.api.tree.Tree.Kind; +import org.sonar.sslr.internal.matchers.InputBuffer; +import org.sonar.sslr.parser.ParseError; +import org.sonar.sslr.parser.ParseErrorFormatter; + +import java.util.Iterator; + +import static org.fest.assertions.Assertions.assertThat; + +public class PHPTreeModelTest { + protected ActionParser p; + + /** + * Parse the given string and return the first descendant of the given kind. + * + * @param s the string to parse + * @param rootRule the rule to start parsing from + * @return the node found for the given kind, null if not found. + */ + protected T parse(String s, PHPLexicalGrammar rootRule) throws Exception { + p = PHPParserBuilder.createParser(rootRule, Charsets.UTF_8); + Tree node = p.parse(s); + checkFullFidelity(node, s); + return (T) node; + } + + /** + * Return the concatenation of all the given node tokens value. + */ + protected static String expressionToString(Tree node) { + return SourceBuilder.build(node).trim(); + } + + private static void checkFullFidelity(Tree tree, String inputString) { + String resultString = expressionToString(tree); + if (!inputString.equals(resultString)) { + if (inputString.startsWith(resultString)) { + String message = "Only beginning of the input string is parsed: " + resultString; + throw new RecognitionException(0, message); + } else { + String message = "Some tokens are lost. See result tree string: " + resultString; + throw new RecognitionException(0, message); + } + } + } +} diff --git a/php-frontend/src/test/java/org/sonar/php/tree/impl/expression/VariableIdentifierTreeTest.java b/php-frontend/src/test/java/org/sonar/php/tree/impl/expression/VariableIdentifierTreeTest.java new file mode 100644 index 0000000000..52bd33f534 --- /dev/null +++ b/php-frontend/src/test/java/org/sonar/php/tree/impl/expression/VariableIdentifierTreeTest.java @@ -0,0 +1,40 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010 SonarSource and Akram Ben Aissi + * sonarqube@googlegroups.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.php.tree.impl.expression; + +import org.junit.Test; +import org.sonar.php.PHPTreeModelTest; +import org.sonar.php.parser.PHPLexicalGrammar; +import org.sonar.plugins.php.api.tree.Tree.Kind; +import org.sonar.plugins.php.api.tree.expression.VariableIdentifierTree; + +import static org.fest.assertions.Assertions.assertThat; + +public class VariableIdentifierTreeTest extends PHPTreeModelTest { + + @Test + public void test() throws Exception { + VariableIdentifierTree tree = parse("$a", PHPLexicalGrammar.EXPRESSION); + + assertThat(tree.is(Kind.VARIABLE_IDENTIFIER)).isTrue(); + assertThat(tree.variableExpression().name()).isEqualTo("$a"); + } + +} diff --git a/php-frontend/src/test/java/org/sonar/php/utils/SourceBuilder.java b/php-frontend/src/test/java/org/sonar/php/utils/SourceBuilder.java new file mode 100644 index 0000000000..ce9d1e73b9 --- /dev/null +++ b/php-frontend/src/test/java/org/sonar/php/utils/SourceBuilder.java @@ -0,0 +1,70 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010 SonarSource and Akram Ben Aissi + * sonarqube@googlegroups.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.php.utils; + +import com.google.common.collect.ImmutableList; +import org.sonar.php.tree.visitors.SubscriptionAstTreeVisitor; +import org.sonar.plugins.php.api.tree.Tree; +import org.sonar.plugins.php.api.tree.Tree.Kind; +import org.sonar.plugins.php.api.tree.lexical.SyntaxToken; + +import java.util.List; + +public class SourceBuilder extends SubscriptionAstTreeVisitor { + + private final StringBuilder stringBuilder = new StringBuilder(); + private int line = 1; + private int column = 0; + + public static String build(Tree tree) { + SourceBuilder writer = new SourceBuilder(); + writer.scanTree(tree); + return writer.stringBuilder.toString(); + } + + @Override + public List nodesToVisit() { + return ImmutableList.of(Tree.Kind.TOKEN); + } + + @Override + public void visitNode(Tree tree) { + SyntaxToken token = (SyntaxToken) tree; + int linesToInsert = token.line() - line; + if (linesToInsert < 0) { + throw new IllegalStateException("Illegal token line for " + token); + } else if (linesToInsert > 0) { + for (int i = 0; i < linesToInsert; i++) { + stringBuilder.append("\n"); + line++; + } + column = 0; + } + int spacesToInsert = token.column() - column; + for (int i = 0; i < spacesToInsert; i++) { + stringBuilder.append(' '); + column++; + } + String text = token.text(); + stringBuilder.append(text); + column += text.length(); + } + +} diff --git a/pom.xml b/pom.xml index d30f12b1a8..abda75fabf 100644 --- a/pom.xml +++ b/pom.xml @@ -95,7 +95,7 @@ true 4.5.2 - 1.20 + 1.21 @@ -133,12 +133,12 @@ ${sonar.version} - org.codehaus.sonar.sslr + org.sonarsource.sslr sslr-core ${sslr.version} - org.codehaus.sonar.sslr + org.sonarsource.sslr sslr-toolkit ${sslr.version} @@ -148,7 +148,7 @@ 2.6 - org.codehaus.sonar.sslr + org.sonarsource.sslr sslr-testing-harness ${sslr.version} diff --git a/sonar-php-plugin/pom.xml b/sonar-php-plugin/pom.xml index 161e22b366..5080be6b28 100644 --- a/sonar-php-plugin/pom.xml +++ b/sonar-php-plugin/pom.xml @@ -54,7 +54,7 @@ test - org.codehaus.sonar.sslr + org.sonarsource.sslr sslr-testing-harness test @@ -92,8 +92,8 @@ - 3200000 - 3000000 + 3700000 + 3500000 ${project.build.directory}/${project.build.finalName}.jar diff --git a/sslr-php-toolkit/pom.xml b/sslr-php-toolkit/pom.xml index 30ec4f18e4..eb0a321daf 100644 --- a/sslr-php-toolkit/pom.xml +++ b/sslr-php-toolkit/pom.xml @@ -18,7 +18,7 @@ ${project.version} - org.codehaus.sonar.sslr + org.sonarsource.sslr sslr-toolkit