Search in sources :

Example 1 with SourceFilePosition

use of com.android.common.ide.common.blame.SourceFilePosition in project buck by facebook.

the class ActionRecorder method recordNodeAction.

/**
     * Record a node action taken by the merging tool.
     *
     * @param mergedElement the merged xml element
     * @param actionType    the action's type
     * @param targetElement the action's target when the action is rejected or replaced, it
     *                      indicates what is the element being rejected or replaced.
     */
synchronized void recordNodeAction(@NonNull XmlElement mergedElement, @NonNull Actions.ActionType actionType, @NonNull XmlElement targetElement) {
    Actions.NodeRecord record = new Actions.NodeRecord(actionType, new SourceFilePosition(targetElement.getDocument().getSourceFile(), targetElement.getPosition()), targetElement.getOriginalId(), null, /* reason */
    mergedElement.getOperationType());
    recordNodeAction(mergedElement, record);
}
Also used : SourceFilePosition(com.android.common.ide.common.blame.SourceFilePosition)

Example 2 with SourceFilePosition

use of com.android.common.ide.common.blame.SourceFilePosition in project buck by facebook.

the class ActionRecorder method recordImplicitRejection.

/**
     * Records when a default value that should be merged was rejected due to a tools:replace
     * annotation.
     *
     * @param attribute              the attribute which default value was ignored.
     * @param implicitAttributeOwner the element owning the implicit default value.
     */
synchronized void recordImplicitRejection(@NonNull XmlAttribute attribute, @NonNull XmlElement implicitAttributeOwner) {
    List<Actions.AttributeRecord> attributeRecords = getAttributeRecords(attribute);
    Actions.AttributeRecord attributeRecord = new Actions.AttributeRecord(Actions.ActionType.REJECTED, new SourceFilePosition(implicitAttributeOwner.getDocument().getSourceFile(), implicitAttributeOwner.getPosition()), attribute.getOriginalId(), null, /* reason */
    AttributeOperationType.REPLACE);
    attributeRecords.add(attributeRecord);
}
Also used : SourceFilePosition(com.android.common.ide.common.blame.SourceFilePosition)

Example 3 with SourceFilePosition

use of com.android.common.ide.common.blame.SourceFilePosition in project buck by facebook.

the class MergingException method getMessage.

/**
     * Computes the error message to display for this error
     */
@NonNull
@Override
public String getMessage() {
    List<String> messages = Lists.newArrayListWithCapacity(mMessages.size());
    for (Message message : mMessages) {
        StringBuilder sb = new StringBuilder();
        List<SourceFilePosition> sourceFilePositions = message.getSourceFilePositions();
        if (sourceFilePositions.size() > 1 || !sourceFilePositions.get(0).equals(SourceFilePosition.UNKNOWN)) {
            sb.append(Joiner.on('\t').join(sourceFilePositions));
        }
        String text = message.getText();
        if (sb.length() > 0) {
            sb.append(':').append(' ');
            // string to the left of a colon.)
            if (!text.startsWith("Error: ")) {
                sb.append("Error: ");
            }
        } else if (!text.contains("Error: ")) {
            sb.append("Error: ");
        }
        //    /my/full/path: /my/full/path (Permission denied)
        if (sourceFilePositions.size() == 1) {
            File file = sourceFilePositions.get(0).getFile().getSourceFile();
            if (file != null) {
                String path = file.getAbsolutePath();
                if (text.startsWith(path)) {
                    int stripStart = path.length();
                    if (text.length() > stripStart && text.charAt(stripStart) == ':') {
                        stripStart++;
                    }
                    if (text.length() > stripStart && text.charAt(stripStart) == ' ') {
                        stripStart++;
                    }
                    text = text.substring(stripStart);
                }
            }
        }
        sb.append(text);
        messages.add(sb.toString());
    }
    return Joiner.on('\n').join(messages);
}
Also used : SourceFilePosition(com.android.common.ide.common.blame.SourceFilePosition) Message(com.android.common.ide.common.blame.Message) File(java.io.File) SourceFile(com.android.common.ide.common.blame.SourceFile) NonNull(com.android.annotations.NonNull)

Example 4 with SourceFilePosition

use of com.android.common.ide.common.blame.SourceFilePosition in project buck by facebook.

the class XmlDocument method addImplicitElements.

/**
     * Add all implicit elements from the passed lower priority document that are
     * required in the target SDK.
     */
// compiler confused about varargs and generics.
@SuppressWarnings("unchecked")
private void addImplicitElements(@NonNull XmlDocument lowerPriorityDocument, @NonNull MergingReport.Builder mergingReport) {
    // if this document is an overlay, tolerate the absence of uses-sdk and do not
    // assume implicit minimum versions.
    Optional<XmlElement> usesSdk = getByTypeAndKey(ManifestModel.NodeTypes.USES_SDK, null);
    if (mType == Type.OVERLAY && !usesSdk.isPresent()) {
        return;
    }
    // check that the uses-sdk element does not have any tools:node instruction.
    if (usesSdk.isPresent()) {
        XmlElement usesSdkElement = usesSdk.get();
        if (usesSdkElement.getOperationType() != NodeOperationType.MERGE) {
            mergingReport.addMessage(new SourceFilePosition(getSourceFile(), usesSdkElement.getPosition()), MergingReport.Record.Severity.ERROR, "uses-sdk element cannot have a \"tools:node\" attribute");
            return;
        }
    }
    int thisTargetSdk = getApiLevelFromAttribute(getTargetSdkVersion(DEFAULT_SDK_VERSION));
    // when we are importing a library, we should never use the build.gradle injected
    // values (only valid for overlay, main manifest) so use the raw versions coming from
    // the AndroidManifest.xml
    int libraryTargetSdk = getApiLevelFromAttribute(lowerPriorityDocument.getFileType() == Type.LIBRARY ? lowerPriorityDocument.getRawTargetSdkVersion(String.valueOf(thisTargetSdk)) : lowerPriorityDocument.getTargetSdkVersion(String.valueOf(thisTargetSdk)));
    // if library is using a code name rather than an API level, make sure this document target
    // sdk version is using the same code name.
    String libraryTargetSdkVersion = lowerPriorityDocument.getTargetSdkVersion(String.valueOf(thisTargetSdk));
    if (!Character.isDigit(libraryTargetSdkVersion.charAt(0))) {
        // this is a code name, ensure this document uses the same code name.
        if (!libraryTargetSdkVersion.equals(getTargetSdkVersion(DEFAULT_SDK_VERSION))) {
            mergingReport.addMessage(getSourceFile(), MergingReport.Record.Severity.ERROR, String.format("uses-sdk:targetSdkVersion %1$s cannot be different than version " + "%2$s declared in library %3$s", getTargetSdkVersion(DEFAULT_SDK_VERSION), libraryTargetSdkVersion, lowerPriorityDocument.getSourceFile().print(false)));
            return;
        }
    }
    // same for minSdkVersion, if the library is using a code name, the application must
    // also be using the same code name.
    String libraryMinSdkVersion = lowerPriorityDocument.getRawMinSdkVersion(String.valueOf(thisTargetSdk));
    if (!Character.isDigit(libraryMinSdkVersion.charAt(0))) {
        // this is a code name, ensure this document uses the same code name.
        if (!libraryMinSdkVersion.equals(getMinSdkVersion(DEFAULT_SDK_VERSION))) {
            mergingReport.addMessage(getSourceFile(), MergingReport.Record.Severity.ERROR, String.format("uses-sdk:minSdkVersion %1$s cannot be different than version " + "%2$s declared in library %3$s", getMinSdkVersion(DEFAULT_SDK_VERSION), libraryMinSdkVersion, lowerPriorityDocument.getSourceFile().print(false)));
            return;
        }
    }
    if (!checkUsesSdkMinVersion(lowerPriorityDocument, mergingReport)) {
        String error = String.format("uses-sdk:minSdkVersion %1$s cannot be smaller than version " + "%2$s declared in library %3$s\n" + "\tSuggestion: use tools:overrideLibrary=\"%4$s\" to force usage", getMinSdkVersion(DEFAULT_SDK_VERSION), libraryMinSdkVersion, lowerPriorityDocument.getSourceFile().print(false), lowerPriorityDocument.getPackageName());
        if (usesSdk.isPresent()) {
            mergingReport.addMessage(new SourceFilePosition(getSourceFile(), usesSdk.get().getPosition()), MergingReport.Record.Severity.ERROR, error);
        } else {
            mergingReport.addMessage(getSourceFile(), MergingReport.Record.Severity.ERROR, error);
        }
        return;
    }
    // if the merged document target SDK is equal or smaller than the library's, nothing to do.
    if (thisTargetSdk <= libraryTargetSdk) {
        return;
    }
    // There is no need to add any implied permissions when targeting an old runtime.
    if (thisTargetSdk < 4) {
        return;
    }
    boolean hasWriteToExternalStoragePermission = lowerPriorityDocument.getByTypeAndKey(USES_PERMISSION, permission("WRITE_EXTERNAL_STORAGE")).isPresent();
    if (libraryTargetSdk < 4) {
        addIfAbsent(mergingReport.getActionRecorder(), USES_PERMISSION, permission("WRITE_EXTERNAL_STORAGE"), lowerPriorityDocument.getPackageName() + " has a targetSdkVersion < 4");
        hasWriteToExternalStoragePermission = true;
        addIfAbsent(mergingReport.getActionRecorder(), USES_PERMISSION, permission("READ_PHONE_STATE"), lowerPriorityDocument.getPackageName() + " has a targetSdkVersion < 4");
    }
    // an app with write permission but not read permission.
    if (hasWriteToExternalStoragePermission) {
        addIfAbsent(mergingReport.getActionRecorder(), USES_PERMISSION, permission("READ_EXTERNAL_STORAGE"), lowerPriorityDocument.getPackageName() + " requested WRITE_EXTERNAL_STORAGE");
    }
    // Pre-JellyBean call log permission compatibility.
    if (thisTargetSdk >= 16 && libraryTargetSdk < 16) {
        if (lowerPriorityDocument.getByTypeAndKey(USES_PERMISSION, permission("READ_CONTACTS")).isPresent()) {
            addIfAbsent(mergingReport.getActionRecorder(), USES_PERMISSION, permission("READ_CALL_LOG"), lowerPriorityDocument.getPackageName() + " has targetSdkVersion < 16 and requested READ_CONTACTS");
        }
        if (lowerPriorityDocument.getByTypeAndKey(USES_PERMISSION, permission("WRITE_CONTACTS")).isPresent()) {
            addIfAbsent(mergingReport.getActionRecorder(), USES_PERMISSION, permission("WRITE_CALL_LOG"), lowerPriorityDocument.getPackageName() + " has targetSdkVersion < 16 and requested WRITE_CONTACTS");
        }
    }
}
Also used : SourceFilePosition(com.android.common.ide.common.blame.SourceFilePosition)

Example 5 with SourceFilePosition

use of com.android.common.ide.common.blame.SourceFilePosition in project buck by facebook.

the class ActionRecorder method recordImpliedNodeAction.

/**
     * Record a node that was added due to an implicit presence in earlier SDK release but requires
     * an explicit declaration in the application targeted SDK.
     * @param xmlElement the implied element that was added to the resulting xml.
     * @param reason optional contextual information whey the implied element was added.
     */
synchronized void recordImpliedNodeAction(@NonNull XmlElement xmlElement, @Nullable String reason) {
    NodeKey storageKey = xmlElement.getOriginalId();
    Actions.DecisionTreeRecord nodeDecisionTree = mRecords.get(storageKey);
    if (nodeDecisionTree == null) {
        nodeDecisionTree = new Actions.DecisionTreeRecord();
        mRecords.put(storageKey, nodeDecisionTree);
    }
    Actions.NodeRecord record = new Actions.NodeRecord(Actions.ActionType.IMPLIED, new SourceFilePosition(xmlElement.getDocument().getSourceFile(), xmlElement.getDocument().getRootNode().getPosition()), xmlElement.getOriginalId(), reason, xmlElement.getOperationType());
    nodeDecisionTree.addNodeRecord(record);
}
Also used : SourceFilePosition(com.android.common.ide.common.blame.SourceFilePosition) NodeKey(com.android.manifmerger.XmlNode.NodeKey)

Aggregations

SourceFilePosition (com.android.common.ide.common.blame.SourceFilePosition)6 NonNull (com.android.annotations.NonNull)1 Message (com.android.common.ide.common.blame.Message)1 SourceFile (com.android.common.ide.common.blame.SourceFile)1 NodeKey (com.android.manifmerger.XmlNode.NodeKey)1 File (java.io.File)1