/*
* Copyright 2012-2015 Sergey Ignatov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.intellij.erlang.inspection;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.psi.PsiElement;
import org.intellij.erlang.psi.*;
import org.jetbrains.annotations.NotNull;
public class ErlangIllegalPatternInspection extends ErlangInspectionBase {
private static final String ERROR = "Illegal pattern";
@Override
protected void checkFile(@NotNull ErlangFile file, @NotNull ProblemsHolder holder) {
for (ErlangFunction function : file.getFunctions()) {
for (ErlangFunctionClause clause : function.getFunctionClauseList()) {
clause.getArgumentDefinitionList().accept(new PatternInspector(holder));
ErlangClauseBody clauseBody = clause.getClauseBody();
if (clauseBody != null) {
clauseBody.accept(new PatternInspector(holder));
}
}
}
}
private class PatternInspector extends ErlangRecursiveVisitor {
private final ProblemsHolder myHolder;
public PatternInspector(ProblemsHolder holder) {
this.myHolder = holder;
}
@Override
public void visitArgumentDefinition(@NotNull ErlangArgumentDefinition o) {
checkExpression(o);
}
@Override
public void visitAssignmentExpression(@NotNull ErlangAssignmentExpression o) {
ErlangExpression leftPart = o.getLeft();
checkExpression(leftPart);
ErlangExpression rightPart = o.getRight();
if (rightPart != null) {
rightPart.accept(this);
}
}
private void checkExpression(@NotNull PsiElement element) {
if (element instanceof ErlangListOpExpression) {
visitGlobalListOpExpression((ErlangListOpExpression) element);
}
else {
checkExpressionAndReport(element, myHolder);
}
}
private void visitGlobalListOpExpression(@NotNull ErlangListOpExpression o) {
ProblemsHolder tempHolder = new ProblemsHolder(myHolder.getManager(), myHolder.getFile(), myHolder.isOnTheFly());
checkExpressionAndReport(o, tempHolder);
if (!tempHolder.getResults().isEmpty()) {
registerProblem(myHolder, o, ERROR);
}
}
private void checkExpressionAndReport(@NotNull PsiElement element, @NotNull final ProblemsHolder problemsHolder) {
element.accept(new ErlangRecursiveVisitor() {
private void registerProblemIfContainsNonConstant(@NotNull ErlangExpression o) {
ConstantExpressionChecker checker = new ConstantExpressionChecker();
o.accept(checker);
if (checker.isNonConstant()) {
registerProblem(problemsHolder, o, ERROR);
}
}
@Override
public void visitAdditiveExpression(@NotNull ErlangAdditiveExpression o) {
registerProblemIfContainsNonConstant(o);
}
@Override
public void visitMultiplicativeExpression(@NotNull ErlangMultiplicativeExpression o) {
registerProblemIfContainsNonConstant(o);
}
@Override
public void visitOrelseExpression(@NotNull ErlangOrelseExpression o) {
registerProblemIfContainsNonConstant(o);
}
@Override
public void visitAndalsoExpression(@NotNull ErlangAndalsoExpression o) {
registerProblemIfContainsNonConstant(o);
}
@Override
public void visitListOpExpression(@NotNull ErlangListOpExpression o) {
if (o.getLeft() instanceof ErlangStringLiteral && o.getRight() != null) {
checkExpressionAndReport(o.getRight(), problemsHolder);
}
else {
registerProblem(problemsHolder, o, ERROR);
}
}
@Override
public void visitCompOpExpression(@NotNull ErlangCompOpExpression o) {
registerProblem(problemsHolder, o, ERROR);
}
@Override
public void visitFunctionCallExpression(@NotNull ErlangFunctionCallExpression o) {
if (o.getQAtom().getMacros() == null) {
registerProblem(problemsHolder, o, ERROR);
}
}
@Override
public void visitCaseExpression(@NotNull ErlangCaseExpression o) {
registerProblem(problemsHolder, o, ERROR);
}
@Override
public void visitReceiveExpression(@NotNull ErlangReceiveExpression o) {
registerProblem(problemsHolder, o, ERROR);
}
@Override
public void visitTryExpression(@NotNull ErlangTryExpression o) {
registerProblem(problemsHolder, o, ERROR);
}
@Override
public void visitListComprehension(@NotNull ErlangListComprehension o) {
registerProblem(problemsHolder, o, ERROR);
}
@Override
public void visitBeginEndExpression(@NotNull ErlangBeginEndExpression o) {
registerProblem(problemsHolder, o, ERROR);
}
@Override
public void visitSendExpression(@NotNull ErlangSendExpression o) {
registerProblem(problemsHolder, o, ERROR);
}
@Override
public void visitCatchExpression(@NotNull ErlangCatchExpression o) {
registerProblem(problemsHolder, o, ERROR);
}
@Override
public void visitFunExpression(@NotNull ErlangFunExpression o) {
registerProblem(problemsHolder, o, ERROR);
}
@Override
public void visitAnonymousCallExpression(@NotNull ErlangAnonymousCallExpression o) {
registerProblem(problemsHolder, o, ERROR);
}
@Override
public void visitIfExpression(@NotNull ErlangIfExpression o) {
registerProblem(problemsHolder, o, ERROR);
}
@Override
public void visitPrefixExpression(@NotNull ErlangPrefixExpression o) {
registerProblemIfContainsNonConstant(o);
}
@Override
public void visitGenericFunctionCallExpression(@NotNull ErlangGenericFunctionCallExpression o) {
registerProblem(problemsHolder, o, ERROR);
}
@Override
public void visitRecordExpression(@NotNull ErlangRecordExpression o) {
if (o.getFirstChild() != o.getRadix()) {
registerProblem(problemsHolder, o, ERROR);
}
}
});
}
}
private static class ConstantExpressionChecker extends ErlangRecursiveVisitor {
private boolean myIsNonConstant;
@Override
public void visitQVar(@NotNull ErlangQVar o) {
myIsNonConstant = true;
}
@Override
public void visitQAtom(@NotNull ErlangQAtom o) {
if (o.getMacros() == null) {
myIsNonConstant = true;
}
}
@Override
public void visitFunctionCallExpression(@NotNull ErlangFunctionCallExpression o) {
if (o.getQAtom().getMacros() == null) {
myIsNonConstant = true;
}
}
public boolean isNonConstant() {
return myIsNonConstant;
}
}
}