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);
}
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);
}
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);
}
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");
}
}
}
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);
}
Aggregations