<commit_before>/*******************************************************************************
 * This file is part of the Polyglot extensible compiler framework.
 *
 * Copyright (c) 2000-2012 Polyglot project group, Cornell University
 * Copyright (c) 2006-2012 IBM Corporation
 * All rights reserved.
 *
 * This program and the accompanying materials are made available under
 * the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * This program and the accompanying materials are made available under
 * the terms of the Lesser GNU Public License v2.0 which accompanies this
 * distribution.
 * 
 * The development of the Polyglot project has been supported by a
 * number of funding sources, including DARPA Contract F30602-99-1-0533,
 * monitored by USAF Rome Laboratory, ONR Grants N00014-01-1-0968 and
 * N00014-09-1-0652, NSF Grants CNS-0208642, CNS-0430161, CCF-0133302,
 * and CCF-1054172, AFRL Contract FA8650-10-C-7022, an Alfred P. Sloan 
 * Research Fellowship, and an Intel Research Ph.D. Fellowship.
 *
 * See README for contributors.
 ******************************************************************************/
package polyglot.ext.jl5.visit;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import polyglot.ast.Node;
import polyglot.ast.NodeFactory;
import polyglot.ext.jl5.ast.AnnotatedElement;
import polyglot.ext.jl5.ast.AnnotationElem;
import polyglot.ext.jl5.types.AnnotationElementValue;
import polyglot.ext.jl5.types.AnnotationElementValueArray;
import polyglot.ext.jl5.types.AnnotationElementValueConstant;
import polyglot.ext.jl5.types.Annotations;
import polyglot.ext.jl5.types.EnumInstance;
import polyglot.ext.jl5.types.JL5ClassType;
import polyglot.ext.jl5.types.JL5Flags;
import polyglot.ext.jl5.types.JL5TypeSystem;
import polyglot.frontend.Job;
import polyglot.types.ClassType;
import polyglot.types.ConstructorInstance;
import polyglot.types.Declaration;
import polyglot.types.FieldInstance;
import polyglot.types.LocalInstance;
import polyglot.types.MethodInstance;
import polyglot.types.Package;
import polyglot.types.SemanticException;
import polyglot.types.Type;
import polyglot.types.TypeSystem;
import polyglot.util.InternalCompilerError;
import polyglot.visit.ContextVisitor;
import polyglot.visit.NodeVisitor;

/** 
 *
 * Visitor that checks annotations of annotated elements 
 *
 */
public class AnnotationChecker extends ContextVisitor {
    public AnnotationChecker(Job job, TypeSystem ts, NodeFactory nf) {
        super(job, ts, nf);
    }

    @Override
    protected Node leaveCall(Node old, Node n, NodeVisitor v)
            throws SemanticException {
        if (n instanceof AnnotatedElement) {
            AnnotatedElement ae = (AnnotatedElement) n;
            return ae.annotationCheck((AnnotationChecker) v);
        }
        return n;
    }

    @Override
    public JL5TypeSystem typeSystem() {
        return (JL5TypeSystem) super.typeSystem();
    }

    /** 
     * 
     * Is the annotation element <code>annotation</code> applicable
     * to Declaration decl? For example, if annotation is "@Override" then decl
     * better be a methodInstance that overrides another method. If annotation's
     * type itself has annotations describing which targets are appropriate,
     * then decl must be an appropriate target.
     * 
     * @param annotation
     * @param decl
     * @throws SemanticException
     */
    public void checkAnnotationApplicability(AnnotationElem annotation,
            Declaration decl) throws SemanticException {
        JL5ClassType annotationType =
                (JL5ClassType) annotation.typeName().type().toClass();

        if (annotationType.equals(typeSystem().OverrideAnnotation())) {
            checkOverrideAnnotation(decl);
        }

        // If annotationType specifies what kind of target it is meant to be applied to,
        // then check that.

        Annotations ra = annotationType.annotations();
        if (ra != null) {
            for (Type at : ra.annotationTypes()) {
                if (at.equals(typeSystem().TargetAnnotation())) {
                    // annotationType has a target annotation!
                    checkTargetMetaAnnotation((AnnotationElementValueArray) ra.singleElement(at),
                                              annotation,
                                              decl);
                }
            }
        }
    }

    protected void checkOverrideAnnotation(Declaration decl)
            throws SemanticException {
        if (!(decl instanceof MethodInstance)) {
            throw new SemanticException("An override annotation can apply only to methods.",
                                        decl.position());
        }
        MethodInstance mi = (MethodInstance) decl;
        JL5TypeSystem ts = this.typeSystem();
        List<MethodInstance> overrides =
                new LinkedList<MethodInstance>(ts.overrides(mi));
        overrides.remove(mi);
        if (overrides.isEmpty()) {
            throw new SemanticException("Method " + mi.signature()
                    + " does not override a method.", decl.position());
        }
    }

    protected void checkTargetMetaAnnotation(
            AnnotationElementValueArray targetKinds, AnnotationElem annotation,
            Declaration decl) throws SemanticException {
        Collection<EnumInstance> eis =
                annotationElementTypesForDeclaration(decl);
        // the array targs must contain at least one of the eis.
        boolean foundAppropriateTarget = false;
        requiredCheck: for (EnumInstance required : eis) {
            for (AnnotationElementValue found : targetKinds.vals()) {
                AnnotationElementValueConstant c =
                        (AnnotationElementValueConstant) found;
                if (required.equals(c.constantValue())) {
                    foundAppropriateTarget = true;
                    break requiredCheck;
                }
            }
        }

        if (!foundAppropriateTarget) {
            throw new SemanticException("Annotation "
                                                + annotation
                                                + " not applicable to this kind of declaration.",
                                        annotation.position());<commit_msg>Use implemented() not overrides() when checking the Override annotation.<commit_after>/*******************************************************************************
 * This file is part of the Polyglot extensible compiler framework.
 *
 * Copyright (c) 2000-2012 Polyglot project group, Cornell University
 * Copyright (c) 2006-2012 IBM Corporation
 * All rights reserved.
 *
 * This program and the accompanying materials are made available under
 * the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * This program and the accompanying materials are made available under
 * the terms of the Lesser GNU Public License v2.0 which accompanies this
 * distribution.
 * 
 * The development of the Polyglot project has been supported by a
 * number of funding sources, including DARPA Contract F30602-99-1-0533,
 * monitored by USAF Rome Laboratory, ONR Grants N00014-01-1-0968 and
 * N00014-09-1-0652, NSF Grants CNS-0208642, CNS-0430161, CCF-0133302,
 * and CCF-1054172, AFRL Contract FA8650-10-C-7022, an Alfred P. Sloan 
 * Research Fellowship, and an Intel Research Ph.D. Fellowship.
 *
 * See README for contributors.
 ******************************************************************************/
package polyglot.ext.jl5.visit;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import polyglot.ast.Node;
import polyglot.ast.NodeFactory;
import polyglot.ext.jl5.ast.AnnotatedElement;
import polyglot.ext.jl5.ast.AnnotationElem;
import polyglot.ext.jl5.types.AnnotationElementValue;
import polyglot.ext.jl5.types.AnnotationElementValueArray;
import polyglot.ext.jl5.types.AnnotationElementValueConstant;
import polyglot.ext.jl5.types.Annotations;
import polyglot.ext.jl5.types.EnumInstance;
import polyglot.ext.jl5.types.JL5ClassType;
import polyglot.ext.jl5.types.JL5Flags;
import polyglot.ext.jl5.types.JL5TypeSystem;
import polyglot.frontend.Job;
import polyglot.types.ClassType;
import polyglot.types.ConstructorInstance;
import polyglot.types.Declaration;
import polyglot.types.FieldInstance;
import polyglot.types.LocalInstance;
import polyglot.types.MethodInstance;
import polyglot.types.Package;
import polyglot.types.SemanticException;
import polyglot.types.Type;
import polyglot.types.TypeSystem;
import polyglot.util.InternalCompilerError;
import polyglot.visit.ContextVisitor;
import polyglot.visit.NodeVisitor;

/** 
 *
 * Visitor that checks annotations of annotated elements 
 *
 */
public class AnnotationChecker extends ContextVisitor {
    public AnnotationChecker(Job job, TypeSystem ts, NodeFactory nf) {
        super(job, ts, nf);
    }

    @Override
    protected Node leaveCall(Node old, Node n, NodeVisitor v)
            throws SemanticException {
        if (n instanceof AnnotatedElement) {
            AnnotatedElement ae = (AnnotatedElement) n;
            return ae.annotationCheck((AnnotationChecker) v);
        }
        return n;
    }

    @Override
    public JL5TypeSystem typeSystem() {
        return (JL5TypeSystem) super.typeSystem();
    }

    /** 
     * 
     * Is the annotation element <code>annotation</code> applicable
     * to Declaration decl? For example, if annotation is "@Override" then decl
     * better be a methodInstance that overrides another method. If annotation's
     * type itself has annotations describing which targets are appropriate,
     * then decl must be an appropriate target.
     * 
     * @param annotation
     * @param decl
     * @throws SemanticException
     */
    public void checkAnnotationApplicability(AnnotationElem annotation,
            Declaration decl) throws SemanticException {
        JL5ClassType annotationType =
                (JL5ClassType) annotation.typeName().type().toClass();

        if (annotationType.equals(typeSystem().OverrideAnnotation())) {
            checkOverrideAnnotation(decl);
        }

        // If annotationType specifies what kind of target it is meant to be applied to,
        // then check that.

        Annotations ra = annotationType.annotations();
        if (ra != null) {
            for (Type at : ra.annotationTypes()) {
                if (at.equals(typeSystem().TargetAnnotation())) {
                    // annotationType has a target annotation!
                    checkTargetMetaAnnotation((AnnotationElementValueArray) ra.singleElement(at),
                                              annotation,
                                              decl);
                }
            }
        }
    }

    protected void checkOverrideAnnotation(Declaration decl)
            throws SemanticException {
        if (!(decl instanceof MethodInstance)) {
            throw new SemanticException("An override annotation can apply only to methods.",
                                        decl.position());
        }
        MethodInstance mi = (MethodInstance) decl;
        JL5TypeSystem ts = this.typeSystem();
        List<MethodInstance> overrides =
                new LinkedList<MethodInstance>(ts.implemented(mi));
        overrides.remove(mi);
        if (overrides.isEmpty()) {
            throw new SemanticException("Method " + mi.signature()
                    + " does not override a method.", decl.position());
        }
    }

    protected void checkTargetMetaAnnotation(
            AnnotationElementValueArray targetKinds, AnnotationElem annotation,
            Declaration decl) throws SemanticException {
        Collection<EnumInstance> eis =
                annotationElementTypesForDeclaration(decl);
        // the array targs must contain at least one of the eis.
        boolean foundAppropriateTarget = false;
        requiredCheck: for (EnumInstance required : eis) {
            for (AnnotationElementValue found : targetKinds.vals()) {
                AnnotationElementValueConstant c =
                        (AnnotationElementValueConstant) found;
                if (required.equals(c.constantValue())) {
                    foundAppropriateTarget = true;
                    break requiredCheck;
                }
            }
        }

        if (!foundAppropriateTarget) {
            throw new SemanticException("Annotation "
                                                + annotation
                                                + " not applicable to this kind of declaration.",
                                        annotation.position());
{'fraction_non_alphanumeric': 0.10145373432812861, 'fraction_numerical': 0.01769094685024229, 'mean_word_length': 2.6096612992781787, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '669610', 'n_tokens_mistral': 3446, 'n_tokens_neox': 3171, 'n_words': 921}